跳至主要內容

构建 ReAct+RAG 智能体:从零打造个性化数字人 Demo

郑天祺大约 13 分钟大模型ReActRAGAI Agent

构建 ReAct+RAG 智能体:从零打造个性化数字人 Demo

前言

在大模型技术迅猛发展的今天,单纯依赖 LLM 的参数知识已无法满足复杂业务场景的需求。ReAct(Reasoning + Acting) 赋予模型动态推理与行动能力,RAG(Retrieval-Augmented Generation) 解决知识实时性与准确性问题,而个性化数字人则将二者融合,为用户提供拥有特定角色设定、记忆与知识体系的 AI 助手。

本文将带你从零开始,构建一个集 ReAct 推理框架 + RAG 知识检索 + 个性化角色记忆 于一体的数字人 Demo,代码可直接运行。

💡 适合读者:有 Python 基础,了解基本 LLM API 调用,对 Agent 开发感兴趣的工程师。


核心概念解析

ReAct 框架

ReAct 由 Yao et al. (2022) 提出,核心思想是让 LLM 在 Reasoning(推理)Acting(行动) 之间交替循环,形成:

Thought → Action → Observation → Thought → Action → ...→ Final Answer
阶段说明示例
Thought模型对当前问题的分析与规划"用户问的是产品价格,我需要查询数据库"
Action调用外部工具或 APIsearch_knowledge_base("产品价格")
Observation工具返回的结果{"price": "¥299", "stock": 50}
Answer基于观测结果生成最终回答"该产品售价 299 元,库存充足"

优势:动态推理,可处理多步骤复杂任务;支持工具调用,突破 LLM 知识局限。


RAG 检索增强生成

RAG 的核心流程:

用户查询 → Embedding 编码 → 向量检索 → 召回相关文档 → 注入 Prompt → LLM 生成答案

关键组件

  • 文档切分:将知识库切成合适的 Chunk(通常 256-512 tokens)
  • 向量数据库:FAISS、Chroma、Milvus 等
  • Embedding 模型text-embedding-ada-002bge-m3
  • 重排序(Rerank):用 Cross-Encoder 对召回结果二次排序,提升精准度

Agent 智能体

Agent = LLM + Memory + Tools + Planning

┌─────────────────────────────────────┐
│              Agent Core             │
│                                     │
│  ┌──────────┐    ┌──────────────┐   │
│  │  Memory  │    │   Planning   │   │
│  │ (短期/长期)│    │  (ReAct Loop)│   │
│  └──────────┘    └──────────────┘   │
│                                     │
│  ┌──────────────────────────────┐   │
│  │           Tools              │   │
│  │  [搜索] [数据库] [API] [代码] │   │
│  └──────────────────────────────┘   │
└─────────────────────────────────────┘

个性化数字人

数字人在 Agent 基础上,额外加入:

  • 角色设定(Persona):姓名、性格、说话风格、专业领域
  • 长期记忆(Long-term Memory):记住用户偏好、历史对话关键信息
  • 个人知识库(Personal KB):特定角色专属的 RAG 知识源
  • 情感状态(Emotion State):根据对话动态调整回应风格

整体架构设计

┌────────────────────────────────────────────────────────────┐
│                    用户输入 (User Query)                     │
└───────────────────────────┬────────────────────────────────┘
                            │
                            ▼
┌────────────────────────────────────────────────────────────┐
│                   数字人角色层 (Persona Layer)               │
│   角色设定 + 长期记忆读取 + 情感状态 → 构建系统 Prompt        │
└───────────────────────────┬────────────────────────────────┘
                            │
                            ▼
┌────────────────────────────────────────────────────────────┐
│               ReAct 推理引擎 (ReAct Engine)                  │
│                                                            │
│   Thought → Action → Observation → ... → Final Answer     │
└──────────┬──────────────────────────────────┬─────────────┘
           │                                  │
           ▼                                  ▼
┌──────────────────────┐         ┌────────────────────────┐
│   RAG 检索模块        │         │    外部工具集            │
│                      │         │                        │
│  个人知识库 (Chroma)  │         │  • 网络搜索              │
│  + Embedding 检索     │         │  • 计算器                │
│  + Rerank 排序        │         │  • 天气 API             │
└──────────────────────┘         └────────────────────────┘
                            │
                            ▼
┌────────────────────────────────────────────────────────────┐
│                   记忆更新层 (Memory Update)                  │
│              提取关键信息 → 写入长期记忆存储                    │
└────────────────────────────────────────────────────────────┘

环境搭建

依赖安装

pip install openai chromadb sentence-transformers tiktoken python-dotenv
pip install langchain langchain-community faiss-cpu

项目结构

digital_human_demo/
├── main.py                 # 主入口
├── config.py               # 配置管理
├── agent/
│   ├── react_agent.py      # ReAct 推理引擎
│   ├── tools.py            # 工具注册
│   └── memory.py           # 记忆管理
├── rag/
│   ├── knowledge_base.py   # 知识库构建
│   ├── retriever.py        # 检索器
│   └── docs/               # 知识文档目录
├── persona/
│   ├── digital_human.py    # 数字人核心
│   └── profiles/           # 角色配置文件
│       └── xiaoai.json     # 示例角色:小艾
└── requirements.txt

环境配置

# config.py
import os
from dotenv import load_dotenv

load_dotenv()

class Config:
    OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
    OPENAI_BASE_URL = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
    LLM_MODEL = os.getenv("LLM_MODEL", "gpt-4o-mini")
    EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "text-embedding-ada-002")
    CHROMA_DB_PATH = "./chroma_db"
    MAX_ITERATIONS = 10          # ReAct 最大循环次数
    TOP_K_RETRIEVAL = 5          # RAG 召回数量
    MEMORY_MAX_ITEMS = 50        # 长期记忆最大条数

ReAct+RAG 智能体实现

知识库构建

# rag/knowledge_base.py
import chromadb
from chromadb.utils import embedding_functions
from langchain.text_splitter import RecursiveCharacterTextSplitter
import os

class KnowledgeBase:
    def __init__(self, collection_name: str, db_path: str = "./chroma_db"):
        self.client = chromadb.PersistentClient(path=db_path)
        
        # 使用 OpenAI Embedding
        self.ef = embedding_functions.OpenAIEmbeddingFunction(
            api_key=os.getenv("OPENAI_API_KEY"),
            model_name="text-embedding-ada-002"
        )
        
        self.collection = self.client.get_or_create_collection(
            name=collection_name,
            embedding_function=self.ef,
            metadata={"hnsw:space": "cosine"}
        )
        
        self.text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=512,
            chunk_overlap=64,
            separators=["\n\n", "\n", "。", "!", "?", ".", "!"]
        )

    def add_documents(self, texts: list[str], metadatas: list[dict] = None):
        """将文档切分后加入知识库"""
        all_chunks = []
        all_ids = []
        all_metas = []
        
        for i, text in enumerate(texts):
            chunks = self.text_splitter.split_text(text)
            for j, chunk in enumerate(chunks):
                all_chunks.append(chunk)
                all_ids.append(f"doc_{i}_chunk_{j}")
                all_metas.append(metadatas[i] if metadatas else {"source": f"doc_{i}"})
        
        # 批量写入(避免单次请求过大)
        batch_size = 100
        for start in range(0, len(all_chunks), batch_size):
            self.collection.add(
                documents=all_chunks[start:start+batch_size],
                ids=all_ids[start:start+batch_size],
                metadatas=all_metas[start:start+batch_size]
            )
        
        print(f"✅ 成功写入 {len(all_chunks)} 个知识块")

    def query(self, query_text: str, top_k: int = 5) -> list[dict]:
        """语义检索"""
        results = self.collection.query(
            query_texts=[query_text],
            n_results=top_k,
            include=["documents", "metadatas", "distances"]
        )
        
        docs = []
        for doc, meta, dist in zip(
            results["documents"][0],
            results["metadatas"][0],
            results["distances"][0]
        ):
            docs.append({
                "content": doc,
                "metadata": meta,
                "score": 1 - dist  # 转换为相似度
            })
        
        return docs

    def load_from_directory(self, dir_path: str):
        """从目录批量加载 .txt / .md 文件"""
        texts, metas = [], []
        for fname in os.listdir(dir_path):
            if fname.endswith((".txt", ".md")):
                fpath = os.path.join(dir_path, fname)
                with open(fpath, "r", encoding="utf-8") as f:
                    texts.append(f.read())
                    metas.append({"source": fname, "type": "file"})
        
        if texts:
            self.add_documents(texts, metas)

ReAct 推理循环

# agent/react_agent.py
from openai import OpenAI
from typing import Callable
import json, re

REACT_SYSTEM_PROMPT = """你是一个智能助手,使用 ReAct 框架解决问题。

每次回复必须严格按照以下格式之一:

格式1(需要使用工具时):
Thought: [你的推理过程]
Action: [工具名称]
Action Input: [工具输入,JSON格式]

格式2(已有足够信息时):
Thought: [你的推理过程]
Final Answer: [最终回答]

可用工具:
{tools_description}

规则:
- 每次只能选择一个 Action
- Action Input 必须是合法 JSON
- 收到 Observation 后继续推理
- 不确定时优先使用 rag_search 工具
"""

class ReActAgent:
    def __init__(self, llm_client: OpenAI, model: str, tools: dict[str, Callable]):
        self.client = llm_client
        self.model = model
        self.tools = tools  # {"tool_name": callable_function}
        self.max_iterations = 10

    def _build_tools_description(self) -> str:
        desc = []
        for name, func in self.tools.items():
            doc = func.__doc__ or "无描述"
            desc.append(f"- {name}: {doc.strip()}")
        return "\n".join(desc)

    def _parse_action(self, text: str) -> tuple[str, str] | None:
        """解析模型输出中的 Action 和 Action Input"""
        action_match = re.search(r"Action:\s*(.+?)(?:\n|$)", text)
        input_match = re.search(r"Action Input:\s*(.+?)(?:\nThought|$)", text, re.DOTALL)
        
        if action_match and input_match:
            action = action_match.group(1).strip()
            action_input = input_match.group(1).strip()
            return action, action_input
        return None

    def _parse_final_answer(self, text: str) -> str | None:
        match = re.search(r"Final Answer:\s*(.+?)$", text, re.DOTALL)
        return match.group(1).strip() if match else None

    def run(self, user_query: str, extra_system: str = "") -> str:
        """执行 ReAct 推理循环"""
        system_prompt = REACT_SYSTEM_PROMPT.format(
            tools_description=self._build_tools_description()
        )
        if extra_system:
            system_prompt = extra_system + "\n\n" + system_prompt

        messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_query}
        ]

        for iteration in range(self.max_iterations):
            print(f"\n{'='*50}")
            print(f"🔄 ReAct 第 {iteration + 1} 轮")
            
            response = self.client.chat.completions.create(
                model=self.model,
                messages=messages,
                temperature=0.1,
                stop=["Observation:"]  # 在 Observation 前停止,等待工具结果
            )
            
            assistant_text = response.choices[0].message.content
            print(f"🤖 模型输出:\n{assistant_text}")

            # 检查是否有最终答案
            final_answer = self._parse_final_answer(assistant_text)
            if final_answer:
                print(f"\n✅ 最终答案:{final_answer}")
                return final_answer

            # 解析并执行 Action
            action_result = self._parse_action(assistant_text)
            if not action_result:
                # 无法解析,直接返回模型输出
                return assistant_text
            
            action_name, action_input_str = action_result
            
            # 执行工具
            try:
                action_input = json.loads(action_input_str)
                if action_name in self.tools:
                    print(f"\n🔧 执行工具:{action_name}({action_input})")
                    observation = self.tools[action_name](**action_input)
                else:
                    observation = f"错误:工具 '{action_name}' 不存在"
            except json.JSONDecodeError:
                observation = f"错误:Action Input 不是合法 JSON:{action_input_str}"
            except Exception as e:
                observation = f"工具执行出错:{str(e)}"
            
            print(f"👁️ 观察结果:{observation}")

            # 将交互历史加入消息
            messages.append({"role": "assistant", "content": assistant_text})
            messages.append({
                "role": "user",
                "content": f"Observation: {observation}\n继续推理:"
            })

        return "达到最大推理轮次,无法得出答案。"

工具注册与调用

# agent/tools.py
from rag.retriever import RAGRetriever
import json

def create_tools(rag_retriever: RAGRetriever) -> dict:
    
    def rag_search(query: str, top_k: int = 3) -> str:
        """从个人知识库中检索相关信息。参数: query(检索关键词), top_k(返回数量)"""
        results = rag_retriever.retrieve(query, top_k=top_k)
        if not results:
            return "知识库中未找到相关内容。"
        
        formatted = []
        for i, r in enumerate(results):
            formatted.append(
                f"[文档{i+1}] 相似度:{r['score']:.2f} 来源:{r['metadata'].get('source','未知')}\n{r['content']}"
            )
        return "\n\n".join(formatted)

    def calculate(expression: str) -> str:
        """执行数学计算。参数: expression(数学表达式字符串,如 '2 + 3 * 4')"""
        try:
            # 安全计算:只允许数字和基本运算符
            allowed = set("0123456789+-*/()., ")
            if all(c in allowed for c in expression):
                result = eval(expression)
                return f"计算结果:{expression} = {result}"
            return "错误:包含不允许的字符"
        except Exception as e:
            return f"计算错误:{e}"

    def get_current_time(timezone: str = "Asia/Shanghai") -> str:
        """获取当前时间。参数: timezone(时区,默认 Asia/Shanghai)"""
        from datetime import datetime
        import pytz
        try:
            tz = pytz.timezone(timezone)
            now = datetime.now(tz)
            return f"当前时间({timezone}):{now.strftime('%Y-%m-%d %H:%M:%S %A')}"
        except Exception:
            from datetime import datetime
            return f"当前时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"

    def summarize_memory(user_id: str) -> str:
        """查询用户历史记忆摘要。参数: user_id(用户ID)"""
        # 实际项目中从数据库读取
        return f"用户 {user_id} 的记忆摘要:该用户是一名AI工程师,偏好技术深度内容,上次询问了关于向量数据库的选型问题。"

    return {
        "rag_search": rag_search,
        "calculate": calculate,
        "get_current_time": get_current_time,
        "summarize_memory": summarize_memory,
    }

个性化数字人集成

角色配置文件

// persona/profiles/xiaoai.json
{
  "name": "小艾",
  "english_name": "Xiaoai",
  "avatar": "🤖",
  "role": "AI技术助手",
  "personality": "专业、耐心、略带幽默,善于用类比解释复杂概念",
  "speaking_style": "中文为主,技术词汇可保留英文,回答结构清晰,善用emoji增加亲和力",
  "expertise": ["LLM应用开发", "RAG系统", "Agent框架", "向量数据库", "Python工程"],
  "knowledge_base": "rag/docs/ai_tech/",
  "greeting": "你好!我是小艾,专注于AI工程实践。有什么技术问题可以问我~ 🚀",
  "memory_prompt": "请记住用户的技术背景和偏好,在后续对话中保持一致性。"
}

角色记忆模块

# agent/memory.py
import json
from datetime import datetime
from collections import deque
from openai import OpenAI

class MemoryManager:
    def __init__(self, user_id: str, llm_client: OpenAI, model: str, max_items: int = 50):
        self.user_id = user_id
        self.client = llm_client
        self.model = model
        self.short_term: list[dict] = []        # 当前会话对话历史
        self.long_term: deque[dict] = deque(maxlen=max_items)  # 跨会话记忆
        self._load_long_term()

    def _storage_path(self) -> str:
        return f"./memory/{self.user_id}_memory.json"

    def _load_long_term(self):
        """从文件加载长期记忆"""
        import os
        path = self._storage_path()
        if os.path.exists(path):
            with open(path, "r", encoding="utf-8") as f:
                data = json.load(f)
                self.long_term = deque(data.get("memories", []), maxlen=50)

    def save_long_term(self):
        """持久化长期记忆"""
        import os
        os.makedirs("./memory", exist_ok=True)
        with open(self._storage_path(), "w", encoding="utf-8") as f:
            json.dump({"user_id": self.user_id, "memories": list(self.long_term)}, f, ensure_ascii=False, indent=2)

    def add_turn(self, role: str, content: str):
        """添加对话轮次到短期记忆"""
        self.short_term.append({
            "role": role,
            "content": content,
            "timestamp": datetime.now().isoformat()
        })

    def extract_and_store_memory(self, conversation: str):
        """用 LLM 从对话中提取关键记忆点"""
        extract_prompt = f"""从以下对话中提取值得长期记忆的关键信息(用户偏好、重要事实、特殊需求等)。
若无重要信息则返回空列表。以 JSON 数组格式返回,每项包含 "content" 和 "category" 字段。

对话内容:
{conversation}

返回格式示例:
[{{"content": "用户是Python开发者,偏好简洁代码风格", "category": "用户背景"}},
 {{"content": "用户对向量数据库选型有疑问,已推荐Chroma", "category": "技术偏好"}}]"""
        
        response = self.client.chat.completions.create(
            model=self.model,
            messages=[{"role": "user", "content": extract_prompt}],
            response_format={"type": "json_object"},
            temperature=0
        )
        
        try:
            result = json.loads(response.choices[0].message.content)
            memories = result if isinstance(result, list) else result.get("memories", [])
            for mem in memories:
                mem["timestamp"] = datetime.now().isoformat()
                self.long_term.append(mem)
            self.save_long_term()
            print(f"💾 提取并保存了 {len(memories)} 条长期记忆")
        except Exception as e:
            print(f"记忆提取失败:{e}")

    def get_memory_context(self) -> str:
        """构建记忆上下文字符串"""
        if not self.long_term:
            return "(暂无历史记忆)"
        
        lines = ["用户历史记忆:"]
        for mem in list(self.long_term)[-10:]:  # 最近10条
            lines.append(f"- [{mem.get('category','其他')}] {mem['content']}")
        return "\n".join(lines)

个性化对话引擎

# persona/digital_human.py
import json
from openai import OpenAI
from agent.react_agent import ReActAgent
from agent.tools import create_tools
from agent.memory import MemoryManager
from rag.knowledge_base import KnowledgeBase

class DigitalHuman:
    def __init__(self, profile_path: str, user_id: str, config):
        # 加载角色配置
        with open(profile_path, "r", encoding="utf-8") as f:
            self.profile = json.load(f)
        
        self.user_id = user_id
        self.config = config
        
        # 初始化 OpenAI 客户端
        self.client = OpenAI(
            api_key=config.OPENAI_API_KEY,
            base_url=config.OPENAI_BASE_URL
        )
        
        # 初始化知识库
        self.kb = KnowledgeBase(
            collection_name=f"persona_{self.profile['name']}",
            db_path=config.CHROMA_DB_PATH
        )
        # 加载角色专属知识
        import os
        kb_path = self.profile.get("knowledge_base", "")
        if kb_path and os.path.exists(kb_path):
            self.kb.load_from_directory(kb_path)
        
        # 初始化记忆管理器
        self.memory = MemoryManager(
            user_id=user_id,
            llm_client=self.client,
            model=config.LLM_MODEL
        )
        
        # 初始化工具集
        tools = create_tools(rag_retriever=self.kb)
        
        # 初始化 ReAct 智能体
        self.agent = ReActAgent(
            llm_client=self.client,
            model=config.LLM_MODEL,
            tools=tools
        )

    def _build_persona_prompt(self) -> str:
        """构建角色系统 Prompt"""
        p = self.profile
        memory_ctx = self.memory.get_memory_context()
        
        return f"""你是 {p['name']}{p['role']}。

【角色设定】
- 性格:{p['personality']}
- 说话风格:{p['speaking_style']}
- 专业领域:{', '.join(p['expertise'])}

【用户记忆】
{memory_ctx}

【行为准则】
1. 始终保持 {p['name']} 的角色特征
2. 结合用户历史记忆提供个性化回答
3. 遇到专业问题,优先使用 rag_search 工具查询知识库
4. 回答后适当引导用户深入探讨
"""

    def chat(self, user_input: str) -> str:
        """处理用户输入,返回数字人回复"""
        print(f"\n{'🤖'*20}")
        print(f"{self.profile['avatar']} {self.profile['name']} 正在思考...")
        
        # 记录用户输入
        self.memory.add_turn("user", user_input)
        
        # 构建角色 Prompt
        persona_prompt = self._build_persona_prompt()
        
        # 通过 ReAct 智能体处理
        response = self.agent.run(
            user_query=user_input,
            extra_system=persona_prompt
        )
        
        # 记录助手回复
        self.memory.add_turn("assistant", response)
        
        # 每 5 轮对话提取一次长期记忆
        if len(self.memory.short_term) % 10 == 0:
            recent_conv = "\n".join([
                f"{t['role']}: {t['content']}" 
                for t in self.memory.short_term[-10:]
            ])
            self.memory.extract_and_store_memory(recent_conv)
        
        return response

    def greet(self) -> str:
        return f"{self.profile['avatar']} {self.profile['greeting']}"

完整 Demo 代码

# main.py - 完整运行入口
from config import Config
from persona.digital_human import DigitalHuman

def main():
    config = Config()
    
    print("=" * 60)
    print("🌟 ReAct + RAG 个性化数字人 Demo")
    print("=" * 60)
    
    # 初始化数字人
    human = DigitalHuman(
        profile_path="persona/profiles/xiaoai.json",
        user_id="user_001",
        config=config
    )
    
    # 打招呼
    print(f"\n{human.greet()}")
    print("\n💡 输入 'quit' 退出,输入 'memory' 查看记忆")
    print("-" * 60)
    
    while True:
        user_input = input("\n👤 你:").strip()
        
        if not user_input:
            continue
        if user_input.lower() == "quit":
            print("\n👋 再见!记忆已保存。")
            human.memory.save_long_term()
            break
        if user_input.lower() == "memory":
            print(f"\n{human.memory.get_memory_context()}")
            continue
        
        response = human.chat(user_input)
        print(f"\n{human.profile['avatar']} {human.profile['name']}{response}")

if __name__ == "__main__":
    main()

运行效果展示

下面是一段 Demo 对话示例:

====================================================
🌟 ReAct + RAG 个性化数字人 Demo
====================================================

🤖 你好!我是小艾,专注于AI工程实践。有什么技术问题可以问我~ 🚀

👤 你:RAG 和 Fine-tuning 各适合什么场景?

🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖🤖
🤖 小艾 正在思考...

==================================================
🔄 ReAct 第 1 轮
🤖 模型输出:
Thought: 用户问的是 RAG 和 Fine-tuning 的场景对比,这是我知识库里的核心内容,先检索相关资料。
Action: rag_search
Action Input: {"query": "RAG Fine-tuning 对比 适用场景", "top_k": 3}

🔧 执行工具:rag_search({"query": "RAG Fine-tuning 对比 适用场景"})
👁️ 观察结果:[文档1] 相似度:0.91 ...

==================================================
🔄 ReAct 第 2 轮
🤖 模型输出:
Thought: 已获取足够信息,可以给出全面对比。
Final Answer: 好问题!两者适用场景确实不同 🎯

**RAG(检索增强生成)适合:**
- ✅ 知识频繁更新(新闻、文档、产品信息)
- ✅ 需要引用来源和溯源
- ✅ 快速部署,成本低
- ✅ 知识量大但使用频率不均匀

**Fine-tuning(微调)适合:**
- ✅ 特定风格/格式的输出(代码补全、特定行业术语)
- ✅ 知识相对固定,追求极致推理速度
- ✅ 有足够的高质量标注数据

**💡 实践建议:** 大多数业务场景优先选 RAG,开发周期短、可解释性强;当发现模型在特定任务上"说话方式"需要调整时,再考虑 Fine-tuning,或者两者结合(先微调获得领域适应,再 RAG 补充实时知识)。

你目前的应用场景是哪类?我可以给更具体的建议~

✅ 最终答案:好问题!...

🤖 小艾:好问题!...

优化方向与进阶思路

1. RAG 质量提升

# 添加 Rerank 模块
from sentence_transformers import CrossEncoder

class ReRanker:
    def __init__(self, model_name="BAAI/bge-reranker-base"):
        self.model = CrossEncoder(model_name)
    
    def rerank(self, query: str, docs: list[dict], top_k: int = 3) -> list[dict]:
        pairs = [(query, doc["content"]) for doc in docs]
        scores = self.model.predict(pairs)
        ranked = sorted(zip(scores, docs), key=lambda x: x[0], reverse=True)
        return [doc for _, doc in ranked[:top_k]]

2. 多模态数字人

  • 集成 TTS(文字转语音):使用 OpenAI TTS API 或 Edge-TTS
  • 集成 数字人形象:SadTalker、Wav2Lip 驱动面部动画
  • 集成 ASR(语音识别):Whisper 实现语音输入

3. 生产化改造

方向技术选型
向量数据库Milvus / Weaviate(替代 Chroma)
记忆存储Redis(短期) + PostgreSQL(长期)
服务化FastAPI + WebSocket 流式响应
监控LangSmith / Langfuse 追踪 ReAct 链路
并发AsyncIO + 连接池优化

4. 多 Agent 协作

用户请求
    │
    ▼
路由 Agent(分类任务类型)
    │
    ├── 技术问题 → 技术小艾(RAG: AI文档库)
    ├── 情感支持 → 心理小暖(RAG: 心理健康知识库)
    └── 商务咨询 → 商务小智(RAG: 行业报告库)

总结

本文完整实现了一个 ReAct + RAG + 个性化数字人 的 Demo 项目,核心要点回顾:

模块技术实现关键作用
ReAct 引擎Thought-Action-Observation 循环多步骤推理与工具调用
RAG 知识库Chroma + OpenAI Embedding知识精准召回
工具集自定义函数注册扩展 Agent 能力边界
角色记忆短期(会话)+ 长期(持久化)个性化交互体验
数字人层Persona Prompt + 记忆注入角色一致性与个性化

整个系统的设计哲学:让 LLM 专注于推理,让 RAG 负责知识,让 Memory 保证连续性,让 Persona 赋予温度。三者协同,打造真正有用、有记忆、有个性的 AI 数字人。

本文涉及技术版本:Python 3.11+,OpenAI SDK 1.x,ChromaDB 0.5.x,LangChain 0.3.x

上次编辑于:
贡献者: zhengtianqi