掘金 人工智能 07月26日 10:15
大模型学习比较-优化提示词改善答疑机器人回答质量
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文详细介绍了大模型的工作原理,从文本分词、向量化到推理输出的整个流程。重点阐述了影响大模型内容生成的随机性参数,如temperature、top_p和top_k,以及seed值的作用。同时,深入探讨了检索增强生成(RAG)技术,包括其工作原理、索引建立、检索与生成过程,以及如何通过多轮对话优化。文章还强调了提示词工程的重要性,提供了构建有效提示词的框架和技巧,并介绍了RAG的自动化评测体系及优化策略,最后触及了Agent和多智能体协作的概念,为理解和应用大模型提供了全面的视角。

⭐大模型工作流程:从文本输入到输出,经历分词、向量化、推理等阶段,其中temperature、top_p、top_k等参数影响生成内容的随机性和多样性,seed值则用于保证结果的可复现性。

💡RAG技术核心:检索增强生成(Retrieval Augmented Generation)通过建立文档索引,检索相关信息后再由大模型生成答案,有效扩展了答疑机器人的知识范围,提高了回答的准确性和相关性。

💬多轮对话优化:在处理长对话时,可将历史对话与当前问题整合成新的查询(query),再进行检索与生成,以应对Embedding模型在长文本上的局限性。

📝提示词工程关键:构建有效的提示词需包含任务目标、上下文、角色、受众、样例和输出格式等要素,清晰的需求表达、角色限定和样例提供是提升模型回答质量的重要技巧。

📊RAG自动化评测与优化:通过Ragas等框架从召回质量、答案忠实度、答案相关性等方面评估RAG系统,并针对性地优化文档切片、检索策略和提示词等环节,以提升整体性能。

🤖Agent与多智能体协作:Agent能够调用外部工具处理复杂任务,通过Planner Agent进行任务规划和多智能体编排,可以实现更复杂的业务流程和更智能的交互。

答疑机器人

大模型如何工作

工作流程

    输入文本分词化
    Token:分词,具有独立语义的词语,每个Token分配一个ID。Token向量化。推理循环输出Token==》输出文本

影响大模型内容生成的随机性参数

    temperature:温度从低到高(0.1 -> 0.7 -> 1.2),概率分布从陡峭趋于平滑,输出也会从相对固定 到逐渐多样化。top_p:范围在0~1。从候选 Token 集合中选出符合条件的“小集合”。具体方法是:按概率从高到低排序,选取累计概率达到设定阈值的 Token 组成新的候选集合,从而缩小选择范围。
    top_k:范围在>=1。从概率排名前k的Token中随机选择一个进行输出。一般来说,top_k越大,生成内容越多样化;top_k越小,内容则更固定。seed:每次模型调用时传入相同的seed值,并保持其他参数不变,模型会尽最大可能返回相同结果。

RAG应用-扩展答疑机器人的知识范围

RAG的工作原理

RAG:Retrieval Argumented Generation

建立索引

文档解析==》分段(切片)==》向量化==》存储索引(向量数据库)

# 加载文档并解析documents = SimpleDirectoryReader('./docs').load_data()# 建立索引(包含切片)index = VectorStoreIndex.from_documents(    documents,    # 指定embedding 模型    embed_model=DashScopeEmbedding(        model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V2    ))

检索+生成

多轮对话

如果将完整历史对话与问题都输入到检索系统,由于字数较多,检索系统可能无法处理(embedding模型在长文本上效果差于短文本)。业界常用的解决方法是:

    通过大模型,基于历史对话信息,将用户的问题改写为一个新的query,新的query将包含历史对话的关键信息。使用新的query,按照原先流程进行检索与生成的过程。
chat_engine = CondenseQuestionChatEngine.from_defaults(    # 查询引擎    query_engine=query_engine,    # 提示词模板    condense_question_prompt=custom_prompt,    # 历史对话记录    chat_history=custom_chat_history,    llm=OpenAILike(        model="qwen-plus-0919",        api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",        api_key=os.getenv("DASHSCOPE_API_KEY"),        is_chat_model=True        ),    verbose=Truestreaming_response = chat_engine.stream_chat("核心职责是什么"))

提示词工程-优化提示词改善答疑机器人回答质量

提示词在很大程度上决定了大模型的回答质量,接下来你可以参考一些提示词框架构建提示词。

提示词框架

from chatbot import rag# 加载索引index = rag.load_index()query_engine = rag.create_query_engine(index=index)# 问答streaming_response = query_engine.query(question)streaming_response.print_response_stream()

基本要素

提示词中需要明确以下几个要素:任务目标、上下文、角色、受众、样例、输出格式。这些要素构成了一个提示词框架,能帮助你构建一个完整、有效的提示词。

要素含义
任务目标(Object)明确要求大模型完成什么任务,让大模型专注具体目标
上下文(Context)任务的背景信息,比如操作流程、任务场景等,明确大模型理解讨论的范围
角色(Role)大模型扮演的角色,或者强调大模型应该使用的语气、写作风格等,明确大模型回应的预期情感
受众(Audience)明确大模型针对的特定受众,约束大模型的应答风格
样例(Sample)让大模型参考的具体案例,大模型会从中抽象出实现方案、需要注意的具体格式等信息
输出格式(Output Format)明确指定输出的格式、输出类型、枚举值的范围。通常也会明确指出不需要输出的内容和不期望的信息,可以结合样例来进一步明确输出的格式和输出方法

提示词自动优化工具:bailian.console.aliyun.com/?tab=app#/c…

提示词模板

直接让用户根据框架书写提示词并非最佳选择。

# 构建提示词模板prompt_template_string = (    "你是公司的客服小蜜,你需要简明扼要的回答用户的问题"    "【注意事项】:\n"    "1. 依据上下文信息来回答用户问题。\n"    "2. 你只需要回答用户的问题,不要输出其他信息\n"    "以下是参考信息。"    "---------------------\n"    "{context_str}\n"    "---------------------\n"    "问题:{query_str}\n。"    "回答:")# 更新提示词模板rag.update_prompt_template(query_engine,prompt_template_string)

构建有效提示词的技巧

    清晰表达需求,并使用分隔符。限定角色和受众。
    角色:大模型扮演什么角色。
    受众:用户扮演什么角色。提供少量样本示例。给模型“思考”的时间。思维连(COT)是让大模型进行思考的一种方式。但是紧靠“思考”无法完成更复杂的工作,大模型也从思维连到多智能体发展。

使用大模型做意图识别

让大模型进行意图识别也有以下两种方法:

推理大模型

from openai import OpenAI# 初始化客户端client = OpenAI(    api_key=os.getenv("DASHSCOPE_API_KEY"),    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1")   

自动化评测

RAG自动化评测体系

从以下几个维度评估:

    召回质量:【检索】正确且相关答案忠实度:【生成】基于检索的上下文答案相关性:【生成】上下文利用率/效率:是否有效利用上下文。

评测框架:Ragas、Trulens、DeepEval

使用Ragas评估

需要准备question、ground_truth。

    Answer Correctness的计算过程。
    召回效果:参考信息的准确度。

如何根据Ragas指标进行优化

    上下文是RAG的生命线。
    Context recall。如果Context recall较低,可以考虑:
    Context precision。如果Context precision较低,可以考虑:
    Answer Correctness。如果Answer Correctness较低,而前两个指标较高,则考虑:

打造卓越的评测体系

建议在实际应用时,邀请 RAG 应用对应的领域专家(人工参与)一起构建能反映真实场景问题分布的测试集,并且持续更新测试集。

优化RAG提升准确度

初步优化检索结果

让大模型获得更多的参考信息

调整代码,检索引擎召回的切片数增加。
==》召回的文档切片存在无关信息,且有效信息未被完全召回。

给大模型结构更清晰的参考信息

Markdown格式是一个很好的选择。(需要重建索引)==》回答准确度能够提高。

RAG的工作流程

文档解析与切片、向量存储、检索与召回参考信息、生成答案。

RAG应用各个环节与改进策略

文档准备阶段

    识别意图空间和知识空间。构建一套可以持续收集用户意图的机制,从而完善知识库,邀请专家参与评测,形成“数据采集-知识更新-专家验证”的闭环流程。

文档解析与切片阶段

    解析:百炼DashScopeParse解析PDF、Word文档。切片:切片方式影响召回质量。

Token切片、句子切片、句子窗口切片、语义切片、Markdown切片

类别 细分类型 改进策略 场景化示例
文档解析 文档类型不统一,部分格式的文档不支持解析 比如前面用到的 SimpleDirectoryLoader 并不支持 Keynote 格式的文件 开发对应格式的解析器,或转换文档格式 例如,某公司使用了大量的 Keynote 文件存储员工信息,但现有的解析器不支持 Keynote 格式。可以开发 Keynote 解析器或将文件转换为支持的格式(如 PDF)。
已支持解析的文档格式里,存在一些特殊内容 比如文档里嵌入了表格、图片、视频等 改进文档解析器 例如,某文档中包含了大量的表格和图片,现有解析器无法正确提取表格中的信息。可以改进解析器,使其能够处理表格和图片。
... ... ...
文档切片 文档中有很多主题接近的内容 比如工作手册文档中,需求分析、开发、发布等每个阶段都有注意事项、操作指导 扩写文档标题及子标题 「注意事项」=>「需求分析>注意事项」 建立文档元数据(打标) 例如,某文档中包含多个阶段的注意事项,用户提问“需求分析的注意事项是什么?”时,系统返回了所有阶段的注意事项。可以通过扩展标题和打标来区分不同阶段的内容。
文档切片长度过大,引入过多干扰项 减少切片长度,或结合具体业务开发为更合适的切片策略 例如,某文档的切片长度过大,包含了多个不相关的主题,导致检索时返回了无关信息。可以减少切片长度,确保每个切片只包含一个主题。
文档切片长度过短,有效信息被截断 扩大切片长度,或结合具体业务开发为更合适的切片策略 例如,某文档中每个切片只有一句话,导致检索时无法获取完整的上下文信息。可以增加切片长度,确保每个切片包含完整的上下文。
... ... ...

切片向量化与存储阶段

文档切片后,需要建立索引,以便后续检索。一种常见方法是使用Embedding模型将切片向量化。

    选择合适Embedding模型。
    百炼的text-embedding-v2、text-embedding-v3。选择合适的向量数据库:内存向量数据库、本地向量数据库、云服务向量数据库(Milvus)

检索召回阶段

主要问题:找出与问题最相关、包含正确答案的切片。

    用户问题不完整、有歧义。==》想办法还原用户意图。检索存在无关信息。==》减少无关信息,避免影响答案生成。

解决:

重点:

    问题改写:
    1)使用大模型扩充用户问题;
    2)将单一查询改为多步骤查询。
    StepDecomposeQueryTransform:复杂问题分解为多步骤;MultiStepQueryEngine:多步骤查询引擎。
    3)假想文档(Hypothetical Document Embeddings)重排序:从向量数据库检索召回3条相关文档片段,但是这3条不一定是事实相关的。百炼提供文本排序模型,对文档做重排序,筛选最相关的3条。提取标签:建立索引时,可以将标签与文档切片一起存储,这种“标签过滤+向量检索”的组合方式,能大幅提升检索准确性。
时机 改进策略 示例
检索前 问题改写 「附近有好吃的餐厅吗?」=> 「请推荐我附近的几家评价较高的餐厅」
问题扩写 通过增加更多信息,让检索结果更全面 「张伟是哪个部门的?」=> 「张伟是哪个部门的?他的联系方式、职责范围、工作目标是什么?」
基于用户画像扩展上下文 结合用户信息、行为等数据扩写问题 内容工程师提问「工作注意事项」=> 「内容工程师有哪些工作注意事项」 项目经理提问「工作注意事项」=> 「项目经理有哪些工作注意事项」
提取标签 提取标签,用于后续标签过滤+向量相似度检索 「内容工程师有哪些工作注意事项」=> 
    标签过滤:{"岗位": "内容工程师"}向量检索:「内容工程师有哪些工作注意事项」
反问用户 「工作职责是什么」=> 大模型反问:「请问你想了解哪个岗位的工作职责」 实现反问的提示词可以参考:10分钟构建能主动提问的智能导购
思考并规划多次检索 「张伟不在,可以找谁」 => 大模型思考规划: => task_1:张伟的职责是什么, task_2:${task_1_result}职责的人有谁 => 按顺序执行多次检索
... ...
检索后 重排序 ReRank + 过滤 多数向量数据库会考虑效率,牺牲一定精确度,召回的切片中可能有一些实际相关性不够高 chunk1、chunk2...、chunk10  => chunk 2、chunk4、chunk5
滑动窗口检索 在检索到一个切片后,补充前后相邻的若干个切片。这样做的原因是:相邻切片之间往往存在语义联系,仅看单个切片可能会丢失重要信息。 滑动窗口检索确保了不会因为过度切分而丢失文本间的语义连接。 常见的实现是句子滑动窗口,你可以用下方的简化形式来理解: 假设原始文本为:ABCDEFG(每个字母代表一个句子) 当检索到切片:D 补充相邻切片后:BCDEF(前后各取2个切片) 这里的BC和EF是D的上下文。比如:
    BC可能包含解释D的背景信息EF可能包含D的后续发展或结果这些上下文信息能帮助你更准确地理解D的完整含义
通过召回这些相关的上下文切片,你可以提高检索结果的准确性和完整性。
... ...

生成答案阶段

    选择合适的大模型。优化提示词模板:
    调整大模型超参:seed、presense_penalty(重复惩罚)、temperature、top_p、max_tokens

插件-Agent

智能体不仅能够与外界交互,还能处理复杂任务,几个核心模块:

from dashscope import Assistants, Messages, Runs, ThreadsChatAssistant = Assistants.create(    # 在此指定模型名称    model="qwen-plus",    # 在此指定Agent名称    name='公司小蜜',    # 在此指定Agent的描述信息    description='一个智能助手,能够查询员工信息,帮助员工发送请假申请,或者查询公司规章制度。',    # 用于提示大模型所具有的工具函数能力,也可以规范输出格式    instructions='''你是公司小蜜,你的功能有以下三个:    1. 查询员工信息。例如:查询员工张三的HR是谁;    2. 发送请假申请。例如:当员工提出要请假时,你可以在系统里帮他完成请假申请的发送;    3. 查询公司规章制度。例如:我们公司项目管理的工具是什么?    请准确判断需要调用哪个工具,并礼貌回答用户的提问。    ''',    # 将工具函数传入    tools=[        {            # 定义工具函数类型,一般设置为function即可            'type': 'function',            'function': {                # 定义工具函数名称,通过map方法映射到query_employee_info函数                'name': '查询员工信息',                # 定义工具函数的描述信息,Agent主要根据description来判断是否需要调用该工具函数                'description': '当需要查询员工信息时非常有用,比如查询员工张三的HR是谁,查询教育部门总人数等。',                # 定义工具函数的参数                'parameters': {                    'type': 'object',                    'properties': {                        # 将用户的提问作为输入参数                        'query': {                            'type': 'str',                            # 对输入参数的描述                            'description': '用户的提问。'                        },                    },                    # 在此声明该工具函数需要哪些必填参数                    'required': ['query']},            }        }    ])# 提前定义好工具函数query_employee_infofunction_mapper = {    "查询员工信息": query_employee_info}new_tool = {'type': 'function',            'function': {                'name': '发送请假申请',                'description': '当需要帮助员工发送请假申请时非常有用。',                'parameters': {                    'type': 'object',                    'properties': {                        # 需要请假的时间                        'date': {                            'type': 'str',                            'description': '员工想要请假的时间。'                        },                    },                    'required': ['date']},            }           }ChatAssistant.tools.append(new_tool)# 提前定义好一个工具函数send_leave_applicationfunction_mapper["发送请假申请"] = send_leave_application

多智能体

当机器人需要在一个请求中执行多个操作时,单个智能体可能无法有效完成所有子任务。

    planner agent
planner_agent = Assistants.create(    model="qwen-plus",    name='流程编排机器人',    description='你是团队的leader,你的手下有很多agent,你需要根据用户的输入,决定要以怎样的顺序去使用这些agent')# 改进planner_agent=Assistants.update(planner_agent.id,instructions="""你的团队中有以下agent。    employee_info_agent:可以查询公司的员工信息,如果提问中关于部门、HR等信息,则调用该agent;    leave_agent:可以帮助员工发送请假申请,如果用户提出请假,则调用该agent;    chat_agent:如果用户的问题无需以上agent,则调用该agent。    你需要根据用户的问题,判断要以什么顺序使用这些agent,一个agent可以被多次调用。你的返回形式是一个列表,不能返回其它信息。比如:["employee_info_agent", "leave_agent"]或者["chat_agent"],列表中的元素只能为上述的agent。""")

将任务规划结果转化为列表对象,逐步解析每个步骤。

import ast# 使用Planner Agent获取任务规划planner_response = get_agent_response(planner_agent, "王五在哪个部门?帮我提交下周三请假的申请")# Planner Agent返回的是一个描述调用顺序的列表形式字符串order_stk = ast.literal_eval(planner_response)
    工具函数summary agent
summary_agent = Assistants.create(    model="qwen-plus",    name='总结机器人',    description='一个智能助手,根据用户的问题与参考信息,全面、完整地回答用户问题',    instructions='你是一个智能助手,根据用户的问题与参考信息,全面、完整地回答用户问题')

完整流程

# 获取Agent的运行顺序agent_order = get_agent_response(planner_agent,query)order_stk = ast.literal_eval(agent_order)cur_query = query# 依次运行Agentfor i in range(len(order_stk)):    cur_agent = agent_mapper[order_stk[i]]    response = get_agent_response(cur_agent,cur_query)    Agent_Message += f"*{order_stk[i]}*的回复为:{response}\n\n"    ...    # 如果当前Agent为最后一个Agent,则将其输出作为Multi Agent的输出    # 如果当前Agent不是最后一个Agent,则将上一个Agent的输出response添加到下一轮的query中,作为参考信息

多智能体编排功能

智能体流程画布的开创者:Dify.ai

    用户直观看到各个智能体的执行规则和链路。编排多个智能体的协作快速验证效果

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

大模型 RAG 提示词工程 智能体 自然语言处理
相关文章