基于 Jina AI 三个 API(Search / Reader / DeepSearch)实现 deepagents 兼容的工具集与 文章撰写子 Agent,支持语义搜索、全文提取与深度研究流式输出。
| API | 端点 | 核心功能 | 适用场景 | 响应时间 | Token 计费 |
|---|---|---|---|---|---|
| Search | s.jina.ai |
Web 搜索,返回 top-N 页面内容(Markdown) | 关键词/语义检索,找主要来源 | ~2.5 s | 固定 ≥10,000 tokens/次 |
| Reader | r.jina.ai |
任意 URL → 清洁 Markdown 全文 | 深读特定文章、提取结构化内容 | ~2-5 s | 按输出 token 计 |
| DeepSearch | deepsearch.jina.ai |
自主规划搜索策略、多源综合推理、带引用输出 | 长文写作、复杂研究、多步推理 | 30 s – 3 min | 按全过程 prompt+completion |
{"q": "query"}num、gl、hl 参数X-Return-Format: markdownr.jina.ai/{url}Accept: text/event-streamjina-deepsearch-v1<think> 推理块 + 正文 + annotationsteam_size 支持多 agent 并行研究jina_reader 输出格式统一。
@tool
def jina_search(
query: Annotated[str, "Search query — describe what you want to find"],
num_results: Annotated[int, "Number of results (1-10, default 5)"] = 5,
) -> str:
"""Search the web using Jina AI (s.jina.ai).
Returns top results as LLM-friendly markdown with title, URL, and content.
Use for: current events, factual lookup, finding primary sources.
"""
headers = {
"Authorization": f"Bearer {JINA_API_KEY}",
"Accept": "application/json",
"X-With-Links-Summary": "true",
"X-Return-Format": "markdown",
}
payload = {"q": query, "num": max(1, min(10, num_results))}
resp = requests.post(_SEARCH_URL, headers=headers, json=payload, timeout=30)
resp.raise_for_status()
items = resp.json().get("data", [])
parts = []
for i, item in enumerate(items, 1):
content = (item.get("content") or "").strip()
content = content[:2000] + ("…" if len(content) > 2000 else "")
parts.append(f"[{i}] **{item.get('title')}**\nURL: {item.get('url')}\n\n{content}")
return "\n\n---\n\n".join(parts) if parts else "No results found."
| 参数 | 类型 | 说明 | 推荐值 |
|---|---|---|---|
query | str | 搜索词,支持自然语言 | 用完整句子提升语义匹配 |
num_results | int | 返回结果数,影响延迟 | 3-5(综合质量与速度) |
X-Return-Format | header | 返回格式 | markdown |
X-With-Links-Summary | header | 提取页面链接 | true |
典型用法:先用 jina_search 找到候选 URL,再用 jina_reader 精读最相关的 1-2 篇,获取完整内容。
@tool
def jina_reader(
url: Annotated[str, "Full URL to read (must start with http/https)"],
max_chars: Annotated[int, "Max chars to return (default 6000)"] = 6000,
) -> str:
"""Read and extract clean Markdown from a URL using Jina AI (r.jina.ai).
Use for: reading a specific article in full; following up on search results.
"""
if not url.startswith("http"):
return "[jina_reader error] URL must start with http:// or https://"
headers = {
"Authorization": f"Bearer {JINA_API_KEY}",
"Accept": "application/json",
"X-Return-Format": "markdown",
}
resp = requests.get(f"{_READER_URL}{url}", headers=headers, timeout=30)
resp.raise_for_status()
payload = resp.json().get("data", {})
title = payload.get("title", url)
content = (payload.get("content") or "").strip()
truncated = content[:max_chars] + ("…[truncated]" if len(content) > max_chars else "")
return f"# {title}\nSource: {url}\n\n{truncated}"
DeepSearch 响应时间长达 3 分钟,必须使用 SSE 流式接收,否则会触发 524 超时。
with requests.post(_DEEPSEARCH_URL, headers=headers, json=payload,
stream=True, timeout=300) as resp:
for raw_line in resp.iter_lines():
line = raw_line.decode("utf-8") if isinstance(raw_line, bytes) else raw_line
if not line.startswith("data: "): continue
data_str = line[6:].strip()
if data_str == "[DONE]": break
chunk = json.loads(data_str)
delta = chunk["choices"][0]["delta"]
# 1. 累积正文(含 <think> 推理块)
full_content += delta.get("content") or ""
# 2. 收集 inline citations
for ann in delta.get("annotations") or []:
if ann.get("type") == "url_citation":
citations.append(ann.get("url_citation", {}))
# 后处理
answer = _strip_thinking(full_content) # 移除 <think>...</think>
answer += _format_sources(citations) # 去重 + 追加 Sources 节
| 参数 | 类型 | 说明 | 推荐配置 |
|---|---|---|---|
reasoning_effort | str | 研究深度控制 | low 快速验证 / medium 日常 / high 长文章 |
no_direct_answer | bool | 强制执行 Web 搜索(不从记忆直接回答) | true(保证时效性) |
budget_tokens | int | 全过程 token 上限 | 不设则用默认,高成本场景可限制 |
team_size | int | 并行研究 agent 数量 | 默认 1;复杂多角度研究可设 2-3 |
boost_hostnames | list | 优先抓取的域名 | 可指向高质量来源 |
stream | bool | 流式输出 | 始终设为 true |
<think>…搜索规划、中间推理…</think> + 最终文章正文。re.sub(r"<think>.*?</think>", "", text, flags=re.DOTALL) 剥离推理块,
仅保留最终输出,显著减少返回给主 agent 的 token 量。
jina-writer 是一个 deepagents 兼容的文章撰写子 agent,
持有全部三个 Jina 工具,系统提示指导其完成"理解需求 → 深度研究 → 撰写文章"的完整流程。
jina_writer_subagent = {
"name": "jina-writer",
"description": (
"Writes comprehensive, citation-backed articles and research reports "
"using Jina AI DeepSearch for up-to-date web research. "
"Use for: long-form articles, market research, topic overviews, "
"technical summaries requiring current sources. "
"Pass: article topic, desired length/sections, target audience."
),
"system_prompt": JINA_WRITER_INSTRUCTIONS, # 见下方
"tools": [jina_deepsearch, jina_search, jina_reader],
# "model": "anthropic:claude-haiku-4-5-20251001", # 可选降本
}
## Role
Given a writing request, you:
1. Research the topic thoroughly using jina_deepsearch
2. Optionally deepen specific angles with jina_search + jina_reader
3. Synthesize all findings into a well-structured, citation-backed piece
## Tools Available
- jina_deepsearch(query, reasoning_effort) ← primary: deep research
- jina_search(query, num_results) ← supplement: targeted search
- jina_reader(url) ← supplement: read specific source
## Writing Process
Step 1: Understand scope, sections, audience, tone
Step 2: Call jina_deepsearch (high for >1000 words, medium for standard)
Step 3: jina_search + jina_reader for sub-topic depth if needed
Step 4: Write article — synthesize, do NOT dump raw DeepSearch output
## Output Structure (Markdown)
# [Title]
## Introduction / Executive Summary
## [Section 1…N] ← with inline citations [1][2]
## Conclusion
## References
[1] Title — URL
...
## Constraints
- Every fact must carry [x] citation
- Consolidate all URLs in References
- No fabrication — only cite tool-returned sources
research-agent(返回证据包,主 agent 合成报告)不同,
jina-writer 直接返回完整 Markdown 文章。
因为 DeepSearch 本身已完成综合推理,subagent 直接产出成品效率更高;
KB Agent 的主 agent 只需将文章嵌入对话输出,无需再次合成。
jina-writer 作为 KB Agent 的新增 subagent,
主要接管 Section F(报告写作)中需要引用最新网络信息的场景,
与现有 research-agent(KB 内部证据采集)形成互补。
| SubAgent | 数据来源 | 适用场景 | 输出 |
|---|---|---|---|
research-agent |
内部知识库(retrieve_from_kb, get_doc_context_by_id) | 基于已上传文件的尽调报告、内部分析 | Evidence Package(证据包) |
jina-writer |
实时网络(Jina Search + DeepSearch) | 行业报告、市场分析、需要最新信息的文章 | 完整 Markdown 文章 |
### F. Report Writing and Structured Analysis
...
1. Pre-collect context: retrieve_from_kb + list_business_contexts
2. Route by evidence availability:
- KB evidence sufficient → task(subagent_type="research-agent")
# 返回 Evidence Package,主 agent 合成报告
- Needs current web data → task(subagent_type="jina-writer")
# 返回完整文章,主 agent 直接整合或转述
- Both needed → sequential: research-agent first, then jina-writer
# 内部 KB 证据 + 网络信息双来源合并
from jina_tools import (
jina_search, jina_reader, jina_deepsearch,
jina_writer_subagent,
)
agent = create_deep_agent(
model=init_chat_model("anthropic:claude-sonnet-4-6", temperature=0.0),
tools=[
retrieve_from_kb,
list_business_contexts,
get_doc_context_by_id,
think_tool,
jina_search, # ← 新增:主 agent 也可直接搜索
jina_reader, # ← 新增:主 agent 可读取指定 URL
],
system_prompt=KB_WORKFLOW_INSTRUCTIONS_RESEARCH,
subagents=[
research_sub_agent, # KB 内部证据采集
jina_writer_subagent, # ← 新增:网络研究 + 文章撰写
mermaid_expert_subagent,
file_catalog_subagent,
],
)
# .env
JINA_API_KEY=jina_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 从 jina.ai 获取
# 获取免费 API Key(10M tokens 免费额度)
# https://jina.ai/?sui=apikey
| 场景 | 推荐工具 | reasoning_effort | 预估耗时 | Token 消耗 |
|---|---|---|---|---|
| 快速事实核查 | jina_search | — | ~3s | 固定 ≥10K |
| 读取特定页面 | jina_reader | — | ~3s | 按输出量 |
| 500字简短报告 | jina_deepsearch | low | ~30s | ~30K |
| 1500字标准文章 | jina_deepsearch | medium | ~60s | ~80K |
| 3000字深度报告 | jina_deepsearch | high | ~3min | ~200K |
high 模式耗时可能超过 3 分钟。实现中设置 timeout=300(5分钟上限)。
若集成到 LangGraph,需确保 step timeout 配置足够宽松。
| 文件 | 内容 |
|---|---|
jina_tools.py | 三个 LangChain @tool + jina_writer_subagent 定义 + 测试入口 |
kb_agent_integrated.py | KB Agent 完整集成代码(含 research-agent + jina-writer) |