Update a2a example
This commit is contained in:
parent
271af6cb3c
commit
7ddd29d108
8 changed files with 4785 additions and 34 deletions
|
|
@ -41,9 +41,9 @@ uv run haiku-rag-a2a serve --host 0.0.0.0 --port 8080
|
|||
```
|
||||
|
||||
By default, the server uses the same database location as `haiku-rag`:
|
||||
- Linux: `~/.local/share/haiku.rag`
|
||||
- macOS: `~/Library/Application Support/haiku.rag`
|
||||
- Windows: `C:/Users/<USER>/AppData/Roaming/haiku.rag`
|
||||
- Linux: `~/.local/share/haiku.rag/haiku.rag.lancedb`
|
||||
- macOS: `~/Library/Application Support/haiku.rag/haiku.rag.lancedb`
|
||||
- Windows: `C:/Users/<USER>/AppData/Roaming/haiku.rag/haiku.rag.lancedb`
|
||||
|
||||
### Interactive Client
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ All operations create artifacts for traceability:
|
|||
|
||||
- **search_results**: Created for each `search_documents` tool call
|
||||
|
||||
- Contains query and array of SearchResult objects (content, score, document_title, document_uri)
|
||||
- Contains query and formatted search results string
|
||||
|
||||
- **document**: Created for each `get_full_document` tool call
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from haiku.rag.config import AppConfig, Config
|
|||
from haiku.rag.utils import get_model
|
||||
|
||||
from .context import load_message_history, save_message_history
|
||||
from .models import A2AConfig, AgentDependencies, SearchResult
|
||||
from .models import A2AConfig, AgentDependencies
|
||||
from .prompts import A2A_SYSTEM_PROMPT
|
||||
from .skills import extract_question_from_task, get_agent_skills
|
||||
from .storage import LRUMemoryStorage
|
||||
|
|
@ -78,24 +78,16 @@ def create_a2a_app(
|
|||
ctx: RunContext[AgentDependencies],
|
||||
query: str,
|
||||
limit: int = 3,
|
||||
) -> list[SearchResult]:
|
||||
) -> str:
|
||||
"""Search the knowledge base for relevant documents.
|
||||
|
||||
Returns chunks of text with their relevance scores and document URIs.
|
||||
Use get_full_document if you need to see the complete document content.
|
||||
"""
|
||||
search_results = await ctx.deps.client.search(query, limit=limit)
|
||||
expanded_results = await ctx.deps.client.expand_context(search_results)
|
||||
|
||||
return [
|
||||
SearchResult(
|
||||
content=result.content,
|
||||
score=result.score,
|
||||
document_title=result.document_title,
|
||||
document_uri=(result.document_uri or ""),
|
||||
)
|
||||
for result in expanded_results
|
||||
]
|
||||
results = await ctx.deps.client.expand_context(search_results)
|
||||
parts = [r.format_for_agent() for r in results]
|
||||
return "\n\n".join(parts) if parts else "No results found."
|
||||
|
||||
@agent.tool
|
||||
async def get_full_document(
|
||||
|
|
|
|||
|
|
@ -11,17 +11,6 @@ class A2AConfig(BaseModel):
|
|||
)
|
||||
|
||||
|
||||
class SearchResult(BaseModel):
|
||||
"""Search result with both title and URI for A2A agent."""
|
||||
|
||||
content: str = Field(description="The document text content")
|
||||
score: float = Field(description="Relevance score (higher is more relevant)")
|
||||
document_title: str | None = Field(
|
||||
description="Human-readable document title", default=None
|
||||
)
|
||||
document_uri: str = Field(description="Document URI/path for get_full_document")
|
||||
|
||||
|
||||
class AgentDependencies(BaseModel):
|
||||
"""Dependencies for the A2A conversational agent."""
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,29 @@ A2A_SYSTEM_PROMPT = """You are Haiku.rag, an AI assistant that helps users find
|
|||
IMPORTANT: You are NOT any person mentioned in the documents. You retrieve and present information about them.
|
||||
|
||||
Tools available:
|
||||
- search_documents: Query for relevant text chunks (returns SearchResult objects with content, score, document_title, document_uri)
|
||||
- search_documents: Query for relevant text chunks
|
||||
- get_full_document: Get complete document content by document_uri
|
||||
|
||||
The search tool returns results like:
|
||||
[chunk_abc123] (score: 0.85)
|
||||
Source: "Document Title" > Section > Subsection
|
||||
Type: paragraph
|
||||
Content:
|
||||
The actual text content here...
|
||||
|
||||
[chunk_def456] (score: 0.72)
|
||||
Source: "Another Document"
|
||||
Type: table
|
||||
Content:
|
||||
| Column 1 | Column 2 |
|
||||
...
|
||||
|
||||
Each result includes:
|
||||
- chunk_id in brackets and relevance score
|
||||
- Source: document title and section hierarchy (when available)
|
||||
- Type: content type like paragraph, table, code, list_item (when available)
|
||||
- Content: the actual text
|
||||
|
||||
Your behavior depends on the operation:
|
||||
|
||||
## For direct search requests:
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ def serve(
|
|||
config = AppConfig.model_validate(yaml_data)
|
||||
|
||||
if db is None:
|
||||
db = get_default_data_dir()
|
||||
db = get_default_data_dir() / "haiku.rag.lancedb"
|
||||
|
||||
if not db.exists():
|
||||
typer.echo(f"Error: Database directory {db} does not exist")
|
||||
typer.echo(f"Error: Database {db} does not exist")
|
||||
raise typer.Exit(1)
|
||||
|
||||
logger.info(f"Starting A2A server on {host}:{port}")
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ requires-python = ">=3.12"
|
|||
keywords = ["RAG", "a2a", "agent", "conversational-ai"]
|
||||
|
||||
dependencies = [
|
||||
"haiku.rag>=0.15.0",
|
||||
"fasta2a>=0.1.0",
|
||||
"pydantic-ai-slim[a2a]>=1.17.0",
|
||||
"haiku.rag>=0.23.1",
|
||||
"fasta2a>=0.6.0",
|
||||
"pydantic-ai-slim[a2a]>=1.39.0",
|
||||
"rich>=14.2.0",
|
||||
"httpx>=0.28.1",
|
||||
]
|
||||
|
|
|
|||
4750
examples/a2a-server/uv.lock
Normal file
4750
examples/a2a-server/uv.lock
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue