-
Notifications
You must be signed in to change notification settings - Fork 4.7k
feat: Add token counting utility + Add support for it in Compression #5593
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 22 commits
bc3cc01
517f2d7
22ab15d
7011c06
8a43877
4c73db2
6f43ed5
ff1e84a
f6e7200
259b5a7
8728502
3e51b13
2fec0e9
4269391
131f190
5d1ed33
5f09d4b
6458a30
be4e3c1
0f17f6d
d568ff0
4dc5a2b
5e7dbeb
bb73ed7
7f4498e
c4a74aa
b38b84b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| """ | ||
| This example shows how to set a context token based limit for tool call compression. | ||
| Run: `python cookbook/agents/context_compression/token_based_tool_call_compression.py` | ||
| """ | ||
|
|
||
| from agno.agent import Agent | ||
| from agno.compression.manager import CompressionManager | ||
| from agno.db.sqlite import SqliteDb | ||
| from agno.models.openai import OpenAIChat | ||
| from agno.tools.duckduckgo import DuckDuckGoTools | ||
|
|
||
| compression_prompt = """ | ||
| You are a compression expert. Your goal is to compress web search results for a competitive intelligence analyst. | ||
|
|
||
| YOUR GOAL: Extract only actionable competitive insights while being extremely concise. | ||
|
|
||
| MUST PRESERVE: | ||
| - Competitor names and specific actions (product launches, partnerships, acquisitions, pricing changes) | ||
| - Exact numbers (revenue, market share, growth rates, pricing, headcount) | ||
| - Precise dates (announcement dates, launch dates, deal dates) | ||
| - Direct quotes from executives or official statements | ||
| - Funding rounds and valuations | ||
|
|
||
| MUST REMOVE: | ||
| - Company history and background information | ||
| - General industry trends (unless competitor-specific) | ||
| - Analyst opinions and speculation (keep only facts) | ||
| - Detailed product descriptions (keep only key differentiators and pricing) | ||
| - Marketing fluff and promotional language | ||
|
|
||
| OUTPUT FORMAT: | ||
| Return a bullet-point list where each line follows this format: | ||
| "[Company Name] - [Date]: [Action/Event] ([Key Numbers/Details])" | ||
|
|
||
| Keep it under 200 words total. Be ruthlessly concise. Facts only. | ||
|
|
||
| Example: | ||
| - Acme Corp - Mar 15, 2024: Launched AcmeGPT at $99/user/month, targeting enterprise market | ||
| - TechCo - Feb 10, 2024: Acquired DataStart for $150M, gaining 500 enterprise customers | ||
| """ | ||
|
|
||
| compression_manager = CompressionManager( | ||
| model=OpenAIChat(id="gpt-5-mini"), | ||
| compress_token_limit=5000, | ||
| compress_tool_call_instructions=compression_prompt, | ||
| ) | ||
|
|
||
| agent = Agent( | ||
| model=OpenAIChat(id="gpt-4o-mini"), | ||
| tools=[DuckDuckGoTools()], | ||
| description="Specialized in tracking competitor activities", | ||
| instructions="Use the search tools and always use the latest information and data.", | ||
| db=SqliteDb(db_file="tmp/dbs/token_based_tool_call_compression.db"), | ||
| compression_manager=compression_manager, | ||
| add_history_to_context=True, # Add history to context | ||
| num_history_runs=3, | ||
| session_id="token_based_tool_call_compression", | ||
| ) | ||
|
|
||
| agent.print_response( | ||
| """ | ||
| Use the search tools and always use the latest information and data. | ||
| Research recent activities (last 3 months) for these AI companies: | ||
|
|
||
| 1. OpenAI - product launches, partnerships, pricing | ||
| 2. Anthropic - new features, enterprise deals, funding | ||
| 3. Google DeepMind - research breakthroughs, product releases | ||
| 4. Meta AI - open source releases, research papers | ||
|
|
||
| For each, find specific actions with dates and numbers.""", | ||
| stream=True, | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -357,6 +357,59 @@ def _format_messages( | |
| # TODO: Add caching: https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference-call.html | ||
| return formatted_messages, system_message | ||
|
|
||
| def count_tokens( | ||
| self, | ||
| messages: List[Message], | ||
| tools: Optional[List[Dict[str, Any]]] = None, | ||
| ) -> int: | ||
| try: | ||
| formatted_messages, system_message = self._format_messages(messages, compress_tool_results=True) | ||
| converse_input: Dict[str, Any] = {"messages": formatted_messages} | ||
| if system_message: | ||
| converse_input["system"] = system_message | ||
|
|
||
| response = self.get_client().count_tokens(modelId=self.id, input={"converse": converse_input}) | ||
| tokens = response.get("inputTokens", 0) | ||
|
|
||
| # Count tool tokens | ||
| if tools: | ||
| from agno.utils.tokens import count_tool_tokens | ||
|
|
||
| includes_system = any(m.role == "system" for m in messages) | ||
| tokens += count_tool_tokens(tools, self.id, includes_system) | ||
|
|
||
| return tokens | ||
| except Exception as e: | ||
| log_warning(f"Failed to count tokens via Bedrock API: {e}") | ||
| return super().count_tokens(messages, tools) | ||
|
||
|
|
||
| async def acount_tokens( | ||
| self, | ||
| messages: List[Message], | ||
| tools: Optional[List[Dict[str, Any]]] = None, | ||
| ) -> int: | ||
| try: | ||
| formatted_messages, system_message = self._format_messages(messages, compress_tool_results=True) | ||
| converse_input: Dict[str, Any] = {"messages": formatted_messages} | ||
| if system_message: | ||
| converse_input["system"] = system_message | ||
|
|
||
| async with self.get_async_client() as client: | ||
| response = await client.count_tokens(modelId=self.id, input={"converse": converse_input}) | ||
| tokens = response.get("inputTokens", 0) | ||
|
|
||
| # Count tool tokens | ||
| if tools: | ||
| from agno.utils.tokens import count_tool_tokens | ||
|
|
||
| includes_system = any(m.role == "system" for m in messages) | ||
| tokens += count_tool_tokens(tools, self.id, includes_system) | ||
|
|
||
| return tokens | ||
| except Exception as e: | ||
| log_warning(f"Failed to count tokens via Bedrock API: {e}") | ||
| return await super().acount_tokens(messages, tools) | ||
|
|
||
| def invoke( | ||
| self, | ||
| messages: List[Message], | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.