Metadata-Version: 2.4
Name: agentlens-framework
Version: 0.1.0
Summary: MCP原生、内置混合RAG、每一步都可观测的轻量Agent框架
Project-URL: Homepage, https://github.com/you/agentlens
Project-URL: Documentation, https://github.com/you/agentlens#readme
Project-URL: Repository, https://github.com/you/agentlens
Project-URL: Issues, https://github.com/you/agentlens/issues
Author-email: Your Name <you@example.com>
License: MIT
License-File: LICENSE
Keywords: agent,ai,llm,mcp,observability,rag
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp>=1.0.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: all
Requires-Dist: agentlens[observatory]; extra == 'all'
Requires-Dist: agentlens[rag]; extra == 'all'
Requires-Dist: anthropic>=0.40.0; extra == 'all'
Requires-Dist: ollama>=0.4.0; extra == 'all'
Requires-Dist: openai>=1.60.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: agentlens[all]; extra == 'dev'
Requires-Dist: mypy>=1.11.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5.0; extra == 'dev'
Provides-Extra: observatory
Requires-Dist: fastapi>=0.115.0; extra == 'observatory'
Requires-Dist: jinja2>=3.1.0; extra == 'observatory'
Requires-Dist: opentelemetry-api>=1.27.0; extra == 'observatory'
Requires-Dist: opentelemetry-sdk>=1.27.0; extra == 'observatory'
Requires-Dist: uvicorn>=0.30.0; extra == 'observatory'
Provides-Extra: rag
Requires-Dist: beautifulsoup4>=4.12.0; extra == 'rag'
Requires-Dist: faiss-cpu>=1.8.0; extra == 'rag'
Requires-Dist: markdown-it-py>=3.0.0; extra == 'rag'
Requires-Dist: numpy>=1.26.0; extra == 'rag'
Requires-Dist: pypdf>=4.0.0; extra == 'rag'
Requires-Dist: rank-bm25>=0.2.2; extra == 'rag'
Requires-Dist: sentence-transformers>=3.0.0; extra == 'rag'
Description-Content-Type: text/markdown

# AgentLens

**MCP-native, hybrid RAG built-in, every step observable — a lightweight Python Agent framework.**

<p align="center">
  <img src="https://img.shields.io/badge/python-3.11+-blue" alt="Python">
  <img src="https://img.shields.io/badge/tests-95%20passed-green" alt="Tests">
  <img src="https://img.shields.io/badge/license-MIT-brightgreen" alt="License">
</p>

```bash
pip install agentlens-framework
agentlens init && agentlens run          # 30 lines, zero API key needed
```

---

## Architecture

```
User Query ──> ReAct Agent ──> LLM (OpenAI / Anthropic / DemoLLM)
                    │
         ┌──────────┼──────────┐
      Tools       Memory    Observatory
         │           │           │
    MCP Client   Conversation  Trace + Cost + Dashboard
         │
    RAG Engine (BM25 + Dense + Cross-encoder Rerank)
```

- **DemoLLM** and **MockEmbedder** replace all real API calls — the entire framework runs without any API key
- **MCP** is a first-class citizen: `MCPToolClient` auto-connects and wraps remote tools
- **Every step** is traced (OpenTelemetry-compatible) and cost-tracked in real time

---

## Quick Start (30 lines)

```python
from agentlens import SyncReActAgent, DemoLLM, tool, ConversationMemory, ApprovalPolicy
import os

@tool(description="Search the web")
async def search(query: str) -> str:
    return f"Results for '{query}': AgentLens is a lightweight Agent framework..."

@tool(description="Read a local file")
async def read_file(path: str) -> str:
    try:
        return open(path, encoding="utf-8").read()[:2000]
    except FileNotFoundError:
        return f"[Error] File not found: {path}"

# Auto-detect API key, fall back to DemoLLM
if os.environ.get("OPENAI_API_KEY"):
    from agentlens import OpenAILLM; llm = OpenAILLM(model="gpt-4o-mini")
else:
    llm = DemoLLM()

agent = SyncReActAgent(
    llm=llm, tools=[search, read_file],
    memory=ConversationMemory(), approval=ApprovalPolicy.AUTO_APPROVE,
)

for step in agent.run("Analyze README.md and search for related info"):
    print(f"[{step.step_number}] {step.thought}")
    if step.action: print(f"  Action: {step.action}({step.action_input})")
    print(f"  {step.latency_ms:.0f}ms | {step.token_usage} tokens\n")
```

Run it:

```bash
python -m agentlens.demo          # zero-dependency demo mode
AGENTLENS_LIVE=1 python -m agentlens.demo   # use real LLM (needs API key)
```

---

## Comparison

AgentLens doesn't aim to be "better" — it aims to be **different**: smaller, faster to start, more transparent.

| | AgentLens | LangChain | LlamaIndex |
|---|---|---|---|
| **Positioning** | Lightweight Agent framework | General LLM orchestration | Data indexing framework |
| **Lines to first Agent** | ~30 | ~100 | ~80 |
| **MCP-native** | Yes | Plugin | No |
| **Built-in hybrid RAG** | BM25 + Dense + Rerank | No | Yes |
| **Zero-API-key demo** | DemoLLM + MockEmbedder | No | No |
| **Observability** | Trace + Cost + Dashboard | Callbacks | Instrumentation |
| **Best for** | Small-medium Agent projects, demos | Complex multi-step pipelines | Document Q&A |

---

## Key Features

### ReAct Agent
```python
from agentlens import SyncReActAgent, OpenAILLM, tool

agent = SyncReActAgent(llm=OpenAILLM(model="gpt-4o-mini"), tools=[...])
for step in agent.run("your task"):
    print(step.thought, step.action, step.observation)
```

### MCP Tool Client
```python
from agentlens import MCPToolClient

async with MCPToolClient("http://localhost:8000") as client:
    tools = await client.list_tools()
    agent = SyncReActAgent(llm=llm, tools=tools)
```

### Hybrid RAG
```bash
agentlens rag index ./docs/ --output ./index/ --embedder mock
agentlens rag search "Python machine learning" --index ./index/
agentlens rag eval --queries queries.jsonl --index ./index/
```

### Observatory & Dashboard
```python
from agentlens import Observatory, ReActAgent

obs = Observatory(tracer=True, cost_tracking=True)
agent = ReActAgent(llm=llm, tools=tools, observatory=obs)
# ...run agent...
print(obs.cost_report())        # token + cost by model
obs.export_traces("trace.json") # full trace export
```

```bash
agentlens serve --port 8848     # Dashboard at http://localhost:8848
agentlens trace list            # list all traces
agentlens trace replay <id>     # step-by-step replay
```

### Custom Tools
```python
from agentlens import tool, ToolBase

@tool(description="Get weather for a city")
async def get_weather(city: str, unit: str = "celsius") -> str:
    return f"{city}: 25C, sunny"

# Or use Pydantic validation
class SearchTool(ToolBase):
    name = "web_search"
    description = "Search the internet"
    class Input(BaseModel):
        query: str
        max_results: int = 5
    async def execute(self, query: str, max_results: int = 5) -> str: ...
```

### Error Handling
```python
from agentlens import ErrorStrategy, RetryConfig

agent = SyncReActAgent(
    llm=llm, tools=tools,
    retry_config=RetryConfig(max_retries=3, backoff_factor=2.0),
    on_error=ErrorStrategy.RETURN_PARTIAL,  # RETRY_THEN_FAIL | SKIP_AND_CONTINUE
)
```

---

## Installation

```bash
# Minimal install (Agent + Tools + Memory)
pip install agentlens-framework

# With RAG engine
pip install agentlens-framework[rag]

# With Dashboard + Tracing
pip install agentlens-framework[observatory]

# Everything
pip install agentlens-framework[all]
```

---

## Project Structure

```
agentlens/
├── core/
│   ├── agent/          # Agent protocol + ReAct implementation
│   ├── llm/            # LLM protocol + adapters (OpenAI, Anthropic, Demo)
│   ├── tools/          # @tool decorator, ToolBase, MCP client
│   ├── memory/         # ConversationMemory, WorkingMemory
│   └── trace/          # Trace/Span models, TraceCollector, TraceStore
├── rag/
│   ├── loader/         # Multi-format document loader (.txt, .md, .pdf, .html)
│   ├── chunker/        # Fixed / recursive / semantic chunking
│   ├── embedder/       # OpenAI API embedder + MockEmbedder
│   ├── retriever/      # BM25 + Dense hybrid retrieval
│   └── query/          # Query rewrite, HyDE, decomposition
├── observatory/
│   ├── facade.py       # Unified Observatory entry point
│   ├── cost.py         # Real-time token counting + cost calculation
│   ├── eval.py         # MRR / NDCG / Recall / Precision
│   └── dashboard/      # FastAPI + Tailwind dashboard
├── cli.py              # Unified CLI: init, run, serve, rag, trace
├── demo.py             # Zero-dependency demo (python -m agentlens.demo)
└── _version.py         # Single source of version truth
```

---

## Roadmap

- [x] ReAct Agent with MCP support
- [x] Hybrid RAG (BM25 + Dense + Rerank)
- [x] Observatory (Trace + Cost + Dashboard)
- [x] Zero-API-key demo mode
- [x] CLI and evaluation tools
- [ ] Multi-agent orchestration
- [ ] Streaming SSE dashboard
- [ ] Langfuse / Weights & Biases integration

---

MIT License. Built to showcase what a production-ready Agent framework looks like in Python.
