当前位置: 首页 > news >正文

实战教程:从零搭建自主查资料的AI智能体

从 0 到 1 搭一个能『自己查资料』的 AI 智能体

一篇能照着做、做完就能跑起来的实战教程。所有数据都在你电脑上。

一、为什么是 AgentScope?

智能体开发框架现在很多:LangChain、LlamaIndex、AutoGen、CrewAI……如果你需要:

  • 开箱即用的 ReAct 范式(思考-行动-观察循环)

  • 官方内置知识库抽象KnowledgeBase+QdrantStore

  • 不写 prompt 模板也能让模型自动调用工具

AgentScope 2.0.x 是一个很好的选择。它是蚂蚁集团开源的多智能体框架,Python API 设计现代(async-first、ContentBlock 列表、统一的 Credential 管理),文档和示例中文友好。

这次要做的事情用一句话概括:

给 AI 一本技术字典,让它回答用户问题前自己翻字典,引用出处再作答。

下面从环境到 UI 一层层拆开,全程可复现。

二、整体架构

项目分四个模块,对应 4 个核心文件:

模块

文件

职责

配置层

config.py

读 .env,构造对话模型、嵌入模型、向量库

知识库

ingest.py

把 5 篇技术文章切片、嵌入、写入 Qdrant

智能体

agent.py

把检索能力封装成FunctionTool,挂到 ReAct Agent

UI

server.py

+static/index.html

Python 标准库 SSE 后端 + 自建前端

四个文件不到 600 行代码,跑通完整 RAG 链路。

数据流

用户提问


[前端 /api/chat SSE]


agent.reply_stream()
│ ┌──────────────────────────────────────┐
├─►│ Thought(思考) │──► SSE: thinking
│ ├──────────────────────────────────────┤
├─►│ Action:调 search_knowledge_base 工具 │──► SSE: tool
│ │ ┌──────────────────────────┐ │
│ │ │ knowledge_base.search() │ │
│ │ │ ↓ Qdrant 向量检索 │ │
│ │ │ ↓ DashScope 实时嵌入 │ │
│ │ └──────────────────────────┘ │
│ ├──────────────────────────────────────┤
├─►│ Observation:检索结果 │──► SSE: sources
│ ├──────────────────────────────────────┤
└─►│ Final Answer:基于结果作答 │──► SSE: token...
│ └──────────────────────────────────────┘

前端流式渲染(token 实时显示、sources 折叠到回答下方)

三、阶段 0:环境准备

# 建隔离 venv
python -m venv .venv
.venv\Scripts\activate

# 安装依赖
pip install agentscope==2.0.4 qdrant-client python-dotenv

确认版本:

python -c "import agentscope; print(agentscope.__version__)"
# → 2.0.4

.env配置:

# 对话模型(DeepSeek)
DEEPSEEK_API_KEY=sk-...
DEEPSEEK_BASE_URL=https://api.deepseek.com
CHAT_MODEL_NAME=deepseek-v4-flash

# 嵌入模型(通义 DashScope)
EMBEDDING_PROVIDER=dashscope
DASHSCOPE_API_KEY=sk-...
DASHSCOPE_EMBEDDING_MODEL=text-embedding-v3
DASHSCOPE_EMBEDDING_DIMENSIONS=1024

# 向量库(本地嵌入式,零运维)
QDRANT_PATH=./qdrant_db

关于模型选型:DeepSeek 目前只提供对话接口,没有 embedding 端点,AgentScope 2.0.4 也不内置DeepSeekEmbeddingModel。所以嵌入层选择 DashScope 的text-embedding-v3(1024 维),对中文支持好、有免费额度。如果你偏好本地部署,也可以换成 Ollama 的嵌入模型,AgentScope 有OllamaEmbeddingModel

Qdrant 文件锁:本地 path 模式下,同一个./qdrant_db目录不能同时被两个进程打开。开发时注意ingest.py和后续脚本不要并行运行。

四、阶段 1:知识库构建

4.1 语料

corpus/下放 5 篇中文技术文章(.md格式),每篇覆盖一个智能体子主题:

corpus/
├── 01-react-推理行动范式.md
├── 02-rag-检索增强生成.md
├── 03-工具调用与function-calling.md
├── 04-多智能体协作.md
└── 05-智能体记忆机制.md

4.2 ingestion 管线

AgentScope 2.0.4 的KnowledgeBase将解析器、分块器、向量库、嵌入模型都拆成可插拔组件。完整的ingest.py

from agentscope.rag import TextParser, ApproxTokenChunker
from config import build_knowledge_base

asyncdefingest(reset: bool = False) -> None:
kb = build_knowledge_base(
name="agent_dev_kb",
description="智能体开发技术知识库",
collection="agent_dev_articles",
)
parser = TextParser()
chunker = ApproxTokenChunker(chunk_size=512, overlap=50)

await kb.ensure_collection()

if reset:
for doc inawait kb.list_documents():
await kb.delete_document(doc.document_id)

for fp insorted(CORPUS_DIR.glob("*.md")):
content = fp.read_text(encoding="utf-8")
sections = await parser.parse(content, fp.name) # 1. 解析
chunks = await chunker.chunk(sections) # 2. 分块
await kb.insert_document( # 3. 嵌入 + 入库
chunks,
document_id=fp.stem,
document_metadata={"filename": fp.name},
)

三步 API:parsechunkinsert_document,全部 async。

注意:检索结果hit.chunk.content的类型是TextBlock 对象(或 TextBlock 列表),不是str。取文本时需做类型判断:

def block_text(c):
if c isNone: return""
ifisinstance(c, str): return c
ifisinstance(c, list):
return"\n".join(
b.text ifhasattr(b, "text") elsestr(b) for b in c
)
returngetattr(c, "text", str(c))

执行导入:

python ingest.py --reset

预期输出:

[ok] 01-react-推理行动范式.md -> 4 chunks
[ok] 02-rag-检索增强生成.md -> 3 chunks
...
导入完成:5 个文档,共 15 个 chunk

五、阶段 2:检索增强 Agent

核心思路:把知识库检索封装成一个FunctionTool,让 Agent 在 ReAct 循环中自主决定何时检索、检索什么。

5.1 FunctionTool 封装

from agentscope.tool import FunctionTool

asyncdef_search_knowledge_base(query: str, top_k: int = 5) -> str:
"""在智能体开发知识库中检索与问题相关的文档片段。"""
kb = build_knowledge_base(KB_NAME, KB_DESC, COLLECTION)
results = await kb.search(query, top_k=top_k)

docs = []
for h in results:
text = block_text(getattr(h.chunk, "content", None))
src = (h.chunk.metadata or {}).get("filename", "未知文档")
score = float(getattr(h, "score", 0.0) or0.0)
docs.append({"source": src, "score": score, "text": text})

global _last_sources
_last_sources.extend(docs)

ifnot docs:
return"未在知识库中找到相关内容。"

return"\n\n".join(
f"[{i}] 来源《{d['source']}》(相关度 {d['score']:.2f})\n{d['text']}"
for i, d inenumerate(docs, 1)
)

retrieval_tool = FunctionTool(
func=_search_knowledge_base,
name="search_knowledge_base",
description=(
"在「智能体开发技术知识库」中检索相关文档片段。"
"当用户询问 Agent / 智能体、ReAct、RAG、工具调用、"
"Function Calling、多智能体协作、记忆机制等开发相关"
"问题时使用本工具获取权威资料。"
),
)

description写得越具体、给的使用场景越多,模型主动调用工具的概率越高。

5.2 构造 ReAct Agent

from agentscope.agent import Agent, ReActConfig
from agentscope.tool import Toolkit
from agentscope.state import AgentState
from agentscope.permission import PermissionContext, PermissionMode

def_build_agent() -> Agent:
model = get_chat_model()
toolkit = Toolkit(tools=[retrieval_tool])
react_config = ReActConfig(max_iters=5)

state = AgentState(
permission_context=PermissionContext(mode=PermissionMode.BYPASS),
)

return Agent(
name="agent_dev_assistant",
system_prompt=_SYSTEM_PROMPT,
model=model,
toolkit=toolkit,
react_config=react_config,
state=state,
)

权限要点:ReAct 的默认权限模式是REQUIRE_USER_CONFIRM,这会导致每次工具调用前等待人工确认,循环不会自动推进。对只读的检索工具,用PermissionMode.BYPASS让 Agent 自主执行。注意:不要把这个模式用于有副作用(写操作、网络请求修改状态)的工具。

5.3 流式事件消费

AgentScope 2.0.4 的流式接口:

async for evt in agent.reply_stream(user_msg):
t = str(getattr(evt, "type", "")).lower()
if t == "text_block_delta": yield ("token", evt.delta)
elif t == "thinking_block_delta": yield ("thinking", evt.delta)
elif t == "tool_call_start": yield ("tool", evt.tool_call_name)

事件type字段是大写字符串(TEXT_BLOCK_DELTATHINKING_BLOCK_DELTATOOL_CALL_START),比对前先.lower()

stream_reply生成器在结束时 yield("sources", deduped)+("done", None),供 UI 区分"正在生成"和"生成完毕"。

六、阶段 3:UI 层

Agent 写好后用命令行交互当然可以跑。但要做展示或分享,一个好看的可视化界面会让体验完全不同。这里没有使用 Gradio——它的默认样式定制空间有限,视觉效果比较单调。取而代之的是Python 标准库 + 自建前端的组合:

选型

说明

后端

http.server.ThreadingHTTPServer

Python 自带,零额外依赖

协议

Server-Sent Events(SSE)

单向流,比 WebSocket 简单;前端用fetch+ReadableStream直接消费

前端

单文件index.html

内联 CSS/JS,零构建步骤

6.1 后端:server.py

整个server.py不到 200 行。关键设计:用后台 daemon 线程运行一个持久事件循环,所有对话请求通过run_coroutine_threadsafe提交。

import asyncio, json, threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

# 持久事件循环:AgentScope 的流式生成器依赖长期存活的 loop
_LOOP = asyncio.new_event_loop()
def_run_loop():
asyncio.set_event_loop(_LOOP)
_LOOP.run_forever()
threading.Thread(target=_run_loop, daemon=True).start()

classHandler(BaseHTTPRequestHandler):
defdo_POST(self):
ifself.path == "/api/chat":
self.send_response(200)
self.send_header("Content-Type", "text/event-stream")
self.end_headers()
fut = asyncio.run_coroutine_threadsafe(pump(), _LOOP)
fut.result(timeout=180)

设计决策说明:为什么用持久 loop 而不是每请求新建?AgentScope 内部(Agent._reasoning、httpxAsyncStream)维护的异步任务生命周期跨越整个 ReAct 循环。每次请求新建 + 销毁 loop 会导致流式协程在中途挂起。用一个 daemon 线程跑run_forever()的持久 loop,和 Gradio 内部 uvicorn 的行为一致。

API 接口:

  • GET /api/stats— 知识库统计(文档数、就绪状态)

  • POST /api/reset— 清空多轮对话历史

  • POST /api/chat— SSE 流,事件类型:token/thinking/tool/sources/done/error

其他几个容易忽略的细节:

  • 服务器绑0.0.0.0而非127.0.0.1。Windows 上部分浏览器把localhost解析为 IPv6::1,只绑 IPv4 地址会导致连接被拒、前端报 "failed to fetch"

  • /api/stats内部的异步调用也要走run_coroutine_threadsafe,不能直接在已运行run_forever()的 loop 上调run_until_complete

  • 确保用项目 venv 的 Python 启动(而非系统或托管 Python),否则会缺少agentscope/qdrant_client等包

6.2 前端:index.html

设计目标:看得像专业聊天产品,同时保持代码简洁(单文件、零依赖)。

侧边栏(288px 固定宽度):

  • 渐变品牌 logo + 应用描述

  • 知识库状态卡(文档数 / 对话模型 / 向量模型)

  • 建议问题 chips,点击自动填入并发送

  • 深色/浅色切换(localStorage 持久化)

  • 清空对话

主聊天区

  • 用户气泡:右对齐,紫色渐变背景

  • 助手气泡:左对齐,白色卡片,带渐变头像

  • 流式阶段:逐 token 显示文本 + 闪烁光标,done后整体渲染 markdown

  • 检索中状态:顶部状态栏显示"正在检索知识库 · search_knowledge_base"

markdown 渲染:流式阶段用renderMdLive实时渲染,自动给未闭合的代码块补上```防止布局抖动;支持标题(h1-h3)、粗体、行内代码、代码块(带语言标注)、有序/无序列表、引用、表格、链接(仅允许 http(s) 或相对路径,其余降至#)。

表格:检测到|...|行时缓冲,遇到非表格行 flush——自动识别表头行 + 分隔行(|---|)+ 数据行,CSS 带斑马纹。

参考来源:用原生<details>元素折叠,每条显示文件名、相关度分数、进度条(分数 × 100%)、180 字片段预览和"展开全文"切换。

深色模式:CSS 自定义属性 +data-theme切换,两套完整的颜色变量。

响应式:窄于 860px 时侧边栏变为抽屉面板(汉堡按钮 + 半透明遮罩)。

整个前端一个文件,约 500 行 CSS + 300 行 JS。

七、技术要点汇总

#

要点

操作

1

DeepSeek 无 embedding 接口

嵌入层选 DashScope(或 Ollama 本地)

2

Qdrant path 模式有文件锁

避免多进程同时访问同一目录

3

chunk.content

是 TextBlock 列表

取文本用block_text()做类型判断

4

ReAct 默认权限会暂停等待确认

只读工具设PermissionMode.BYPASS

5

流式事件 type 是大写字符串

比对前先.lower()

6

AgentScope 流式依赖持久事件循环

后台 daemon 线程 +run_coroutine_threadsafe

7

/api/stats

不能在已运行的 loop 上调run_until_complete

统一用run_coroutine_threadsafe

8

服务器绑127.0.0.1可能被 IPv6 跳过

0.0.0.0

9

用错 Python 解释器会导致包找不到

始终用 venv 的 python.exe

八、跑起来

# 1. 环境
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # 填入 DEEPSEEK_API_KEY、DASHSCOPE_API_KEY

# 2. 灌库
python ingest.py --reset

# 3. 启动
python server.py
# → http://localhost:8000

打开浏览器即可使用:提问、看流式回答、展开来源引用、切换主题。

九、接下来可以做什么

这个版本已经完整跑通 RAG + ReAct 范式,以下是可以继续增强的方向:

  • 查询改写:用户口语化问题先让 LLM 重写成更适合检索的关键词组,命中率会明显提升

  • Reranker:检索 Top-5 后用小模型重排(如 bge-reranker-v2),答案质量上一档

  • 流式工具结果:把工具返回从一次性的整段文本改成边检索边输出的细粒度流

  • 多轮对话压缩:长对话超出 token 上限时,用 sliding window 或自动摘要裁剪上下文

  • 权限分级:把 BYPASS 拆成只读 / 可写的两套权限,写操作保留人工确认

  • 多知识库:把不同领域的文档放入独立知识库,让 Agent 根据问题自动路由到对应知识库

这些扩展点都在 AgentScope 2.0.4 的原生支持范围内,不需要改框架就能做到。


技术栈:AgentScope 2.0.4 / DeepSeek-v4-flash / DashScope text-embedding-v3 / Qdrant (本地嵌入式) / Python 3.13 / 零额外 UI 依赖

代码量:~600 行 Python + ~800 行 HTML/CSS/JS

http://www.jsqmd.com/news/1194779/

相关文章:

  • MusicFree插件化音乐播放器:如何快速打造你的个性化免费音乐库
  • 现代C:标准库:字符、字符串处理与数学计算
  • 告别VBA!用ChatGPT新功能一键生成精美PPT(附实战案例)
  • 重测序基因组:Pi核酸多样性在群体遗传选择分析中的应用
  • 3分钟解锁Wand游戏修改器:开源增强工具的完整使用指南
  • 2026年低延迟Agent数据库哪家专业:实时查询引擎、数据新鲜度与AI场景适配深度解析 - 科技焦点
  • EmojiOne Color 终极免费彩色表情字体完整使用指南
  • “不得”“应当”“鼓励”三类模态词自动归类准确率提升至99.7%——基于ChatGPT-4o微调的政策语义解析引擎(仅限首批200家政务云平台内测)
  • Deep-Live-Cam终极指南:3分钟掌握实时AI换脸核心技术
  • 树莓派5+Hailo AI加速帽部署自定义YOLO模型实战
  • ZEQP WMS:如何快速搭建企业级开源仓库管理系统
  • 南京首饰怎么卖高价?添价收专业鉴定保留品牌溢价 - 分享测评官
  • ENScan_GO:5分钟快速掌握企业信息收集的终极工具
  • Windows笔记本续航焦虑终结者:EnergyStarX智能电池优化实战指南
  • Obsidian插件推荐:T0与T1级别必装清单及外置工具扩展
  • # 2026年天津劳动争议律师推荐 高延庆律师全程亲办案例扎实 - 本地品牌推荐
  • 终极指南:如何用Layerdivider 5分钟实现专业PSD智能分层
  • 告别静态沙盘值守|视频孪生活态感知,重塑边境岸线智能主动防御新体系
  • 长沙雨花区房屋修缮上门|维小达|专业墙面维修、窗户维修、吊顶维修、壁纸壁布、瓷砖维修、瓷砖美缝、石材修复等一站式房屋修缮服务 - 一点传媒
  • 美妆oem是什么意思?14年工厂老板告诉你:不懂这3个品控细节,代工就是交学费
  • BlindWatermark完整指南:Java图像盲水印的终极解决方案
  • FreeRTOS系列|内存管理五:heap_5实战与多区域堆配置
  • 2026 建材行业:一线瓷砖品牌盘点(十大品牌)
  • 3大核心功能深度评测:鸣潮工具箱如何重塑你的游戏体验
  • 数字化会务新范式:会助力智能会务系统一站式会议管理系统解决方案
  • 办房产证委托书公证 2026 年如何办理?线上办理方法分享 - 跑政通
  • 别让预算卡住GEO第一步:2026中小企业如何用低成本工具实现品牌AI可见性监测
  • C++与TwinCAT 3通过ADS通讯:原理、实战与性能优化指南
  • 免费AI音频分离:在Audacity中一键提取人声和伴奏的完整方案
  • 从404到5xx:后端接口调试中那些“似是而非”的HTTP状态码实战解析