We are building a research synthesis agent that accepts a user topic, plans parallel search queries against a mock knowledge base, and returns a structured markdown report. This pattern is the backbone of support triage, sales intelligence, and any workload where an LLM must gather context before it acts.
What you'll need
Python 3.10 or newer. The OpenAI SDK: pip install openai. An Oxlo.ai API key from https://portal.oxlo.ai. That is it. Oxlo.ai handles the inference, and because it bills per request instead of per token, a multi-turn agent loop with long context stays predictable. See https://oxlo.ai/pricing for plan details.
Step 1: Set up the Oxlo.ai client
Before we write agent logic, we verify the connection. I use llama-3.3-70b here because it is a reliable general-purpose flagship, but Oxlo.ai also offers qwen-3-32b and kimi-k2.6 if you need stronger agentic reasoning.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Say 'Oxlo.ai connection OK' and nothing else."},
],
)
print(response.choices[0].message.content)
Step 2: Define the search tool and knowledge base
Agentic workloads need tools. We define a simple in-memory knowledge base and a Python function that the LLM will call. In production you would swap this for a vector database or internal API.
KNOWLEDGE_BASE = {
"python asyncio": "Asyncio is a library to write concurrent code using the async/await syntax.",
"oxlo.ai pricing": "Oxlo.ai uses per-request pricing. One flat cost per API request regardless of prompt length.",
"agentic workflows": "Agentic workflows involve LLMs making decisions and using tools across multiple steps.",
}
def search_knowledge_base(query: str) -> str:
query_lower = query.lower()
results = []
for key, value in KNOWLEDGE_BASE.items():
if any(word in key for word in query_lower.split()):
results.append(f"{key}: {value}")
return "\n".join(results) if results else "No results found."
TOOLS = [
{
"type": "function",
"function": {
"name": "search_knowledge_base",
"description": "Search the internal knowledge base for a given topic.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query.",
}
},
"required": ["query"],
},
},
}
]
Step 3: Write the agent system prompt
The system prompt is the contract. It tells the model how to plan searches, call tools, and format the final report. Keep it explicit.
SYSTEM_PROMPT = """You are a research synthesis agent. Your job is to help the user understand a topic by searching an internal knowledge base and producing a structured markdown report.
Follow these rules:
1. Plan 1 to 3 search queries to gather relevant facts.
2. Call the search_knowledge_base tool for each query.
3. After you receive the search results, synthesize them into a concise markdown report with a title, key findings, and a summary.
4. Do not make up facts. Only use information returned by the tool."""
Step 4: Build the multi-step agent loop
This is the engine. We run a loop that sends the conversation to Oxlo.ai, checks for tool calls, executes them in Python, and feeds the results back. The loop caps at three steps to avoid runaway execution.
import json
def run_agent(user_query: str, max_steps: int = 3) -> str:
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_query},
]
for _ in range(max_steps):
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
tools=TOOLS,
tool_choice="auto",
)
assistant_message = response.choices[0].message
messages.append(assistant_message)
if not assistant_message.tool_calls:
return assistant_message.content
for tool_call in assistant_message.tool_calls:
func_name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
if func_name == "search_knowledge_base":
observation = search_knowledge_base(args["query"])
else:
observation = "Unknown tool."
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": func_name,
"content": observation,
})
# Force final answer if max steps reached
messages.append({"role": "user", "content": "Please provide the final report now."})
final = client.chat.completions.create(
model="llama-3.3-70b",
messages=messages,
)
return final.choices[0].message.content
Step 5: Execute the pipeline
Now we wire the pieces together and run a query. This script initializes the conversation, runs the agent, and prints the synthesized report.
if __name__ == "__main__":
query = "Explain how Oxlo.ai pricing works for agentic workloads."
report = run_agent(query)
print(report)
Run it
Save the full script as research_agent.py, replace YOUR_OXLO_API_KEY, and run python research_agent.py. Here is what the output looks like for the query above.
# Oxlo.ai Pricing for Agentic Workloads
## Key Findings
- Oxlo.ai uses a per-request pricing model. One flat cost is charged per API request regardless of prompt length.
- This differs from token-based providers, where cost scales with input and output tokens.
- For agentic workloads, which often involve long context windows and multiple back-and-forth turns, per-request pricing keeps costs predictable.
## Summary
Agentic systems on Oxlo.ai can pass large contexts and chain multiple tool calls without the price increasing with each additional token. This makes it a cost-effective platform for building multi-step agents.
Wrap-up
Two concrete next steps. First, replace the mock dictionary with a real vector database or internal search API. Second, add a persistence layer, SQLite or Redis, so the agent can resume long-running research tasks across multiple sessions. Oxlo.ai's request-based pricing means adding those extra context turns will not balloon your bill the way token-based providers do, which makes it a strong fit for agentic systems that iterate.
Top comments (0)