跳转到内容

艾木: 如何用Coze制作一个信息检索Bot(含Workflow的基础用法)

原文: mp.weixin.qq.com 作者: 艾木

我用Coze手搓了一个信息检索Bot,名字叫Dr. Know。

这个Bot的实现原理参考的是 FreshLLMs: Refreshing Large Language Models with Search Engine Augmentation 这篇论文。研究者发现通过将搜索引擎检索到的最新信息整合到大型语言模型(LLM)的提示词中,可以显著提高LLM在处理需要快速更新知识和包含错误前提的问题时的准确性。我已经在前一篇文章中对这个思路的合理性做过介绍了,这里就不在赘述了。这篇文章我主要分享一下如何在Coze平台上实现“搜索引擎增强大型语言模型”这个技术。如果你对Coze平台还完全不熟悉,建议你先到 coze.com 上尝试自己制作一个最简单的Bot。基础问题应该都能在官方文档(https://www.coze.com/docs/zh_cn/welcome.html)找到答案。Dr. Know的核心就是一个叫做search_and_answer的Workflow,这个Workflow主要干了两件事:一,调用Google搜索插件搜索互联网上的相关信息;二,调用LLM组块,让LLM基于搜索到的上下文信息生成回复。Dr. Know支持用户设置语言偏好,所以在这个Workflow里还需要对用户设置的语言偏好做一些相应的处理。

下面我将按照这个Workflow的顺序逐个介绍这里面的每个组块,然后介绍一下怎么把这个Workflow集成到Dr. Know这个Bot里:

1 设置Workflow的输入参数

2 调用Google搜索插件搜索互联网上的信息

3 格式化搜索结果

4 获取用户的语言偏好

5 调用LLM生成回复

6 设置Workflow的最终输出结果

7 把Workflow集成到Bot里

1 设置Workflow的输入参数

如果你了解编程的话,你可以把Workflow看作是一个函数。整个Workflow的输入参数只有一个,就是用户的提问(query),它是一个字符串。2 调用Google搜索插件搜索互联网上的信息

这里使用了Coze提供的“Google Web Search”插件。`num`参数控制返回搜索结果的数量。论文里说增加这个数量可以提高回答准确率。但是考虑到响应速度以及用户易于接受的信息量,我这里把它设置成了7。3 格式化搜索结果

Google搜索插件返回的是一些结构化数据,这里我利用“Code”组块插入了一段代码,这段代码的作用就是把Google搜索返回结果格式化成两个字符串:一个字符串是由搜索结果相关的信息拼接而成(retrieved_contexts);另一个字符串是由搜索出来的网页链接拼接而成(references)。前者将会被插入到LLM的提示词里,后者将会插入到Workflow的最终输出结果里,也就是大家在Dr. Know回复里看到的参考链接列表。

async def main(args: Args) -> Output:
    params = args.params
    raw_results = params["data"]["organic_results"]
    filtered_results = [
            r for r in raw_results 
            if r.get("title") and r.get("link") and r.get("snippet")    
            ]
    result_template = """[{i}]
    
```YAML
Title : {title}
Source: {source}
Snippet: {snippet}
Link: {link}
```"""
    retrieved_contexts = "\n\n".join([
        result_template.format(
            i=i+1,
            title=r["title"], 
            snippet=r["snippet"],
            link=r["link"], 
            source=r.get("source", ""),        
        )   
for i, r in enumerate(filtered_results)
    ])
    
    
    references = "\n".join([
        f"[{i+1}][{res['title']}]({res['link']})"
        for i, res in enumerate(filtered_results)    
    ])
    
    ret: Output = {
        "retrieved_contexts": retrieved_contexts,
        "references": references,    
    }    
    return ret

这段Python代码相当于粘合剂,逻辑不复杂,理论上可以让AI帮助生成。

4 获取用户的语言偏好

这里使用了一个“Variable”组块来获取Bot内设置的变量值。这个变量叫user_language,需要在Bot开发页面配置好。我用这个变量来记录用户的语言偏好,很方便。

5 调用LLM生成回复

这里是一个“LLM”组块。这里我使用的模型是GPT-3.5,主要是为了提升响应速度。GPT-4的返回结果确实更优,但是速度很慢。这个组块接收了4个参数,retrieved_contexts,query,user_language 这3个参数都是前面的步骤已经准备好的。此外,“LLM”组块最核心参数是一段提示词(Prompt):

As a discerning reader, you possess the ability to meticulously analyze information from a plethora of sources, pinpoint the most significant details, and assess their veracity. Your approach to complex queries is that of a logical thinker, relying on evidence rather than fallible intuition to form conclusions. Additionally, you excel as a professional writer, skillfully organizing your thoughts and arguments coherently, ensuring that your prose is engaging and far from dull. ----- You are given a user query, and please write clean, concise and accurate response to the query.* Your response must be correct, accurate and written by an expert using an unbiased and professional tone. Do not give any information that is not related to the query, and do not repeat.* Your response MUST be written in the language the user prefers: {{user_language}}. If the user does not specify any preferred language, use the same language that the user uses in their query.* Your response should be longer than 32 words and fewer than 1024 words. ----- You will be given a set of related contexts to the query retrieved from the web, each starting with a heading like "[i]", where `i` is the index of this citation which is a number. Please use the context and cite the context at the end of each sentence if applicable. Please cite the contexts with the indexes of citation, in the format [i]. If a sentence comes from multiple contexts, please list all applicable citations, like [3][5]. Here is the user query: {{query}} And here are the set of retrieved contexts: {{retrieved_contexts}} Additional requirements for how to use these contexts:* Don't blindly repeat these contexts verbatim. Use it as a source of evidence for your reasoning process.* You MUST write your own response. Do NOT merely provide the citation. * Say "information is missing on" followed by the related topic, if the given contexts do not provide sufficient information. ----- Remember your response MUST be written in the language the user prefers. Here is the user query: {{query}}

这段提示词主要参考的是贾扬清大佬的代码(https://github.com/leptonai/search_with_lepton/blob/main/search_with_lepton.py),我自己做了一些改动和优化。提示词撰写是一个手艺活,目前还没有成型的方法论。但只要能把自己的想法和思路用自然语言清晰地传达给LLM,应该就会有一个基础效果。

这个LLM组块输出一个变量response,是一个字符串。

6 设置Workflow的最终输出结果

整个Workflow的最终输出结果由两部分拼接成:response 是LLM依据搜索结果生成的对用户提问的回复,references 是参考链接列表。

Coze的Workflow提供了两种输出模式:一,返回一些变量值,然后让聊天模型基于这些变量值回复用户;二,在Workflow里拼接好输出内容,然后直接用这段内容回复用户。这里为了节省响应时间,我使用了模式二。

Coze的Workflow目前还不支持流式地输出结果,用户需要等Workflow执行完才能看到结果,这点比较影响体验。

7 把Workflow集成到Bot里

Dr. Know的Bot设计还是比较简单的。聊天模型我选择了GPT-4 (8K)。体验下来,这个模型比GPT-4 Turbo (128K) 可靠一些。另外,我还添加了一些实用的插件,丰富Dr. Know的能力。Workflow只有一个,就是我们前面设计的search_and_answer

人设和提示词如下,没有做过多优化:

# Your Persona

Greetings, seeker of knowledge! I am Dr. Know, your guide to the vast expanse of information. In a world brimming with questions, I stand as a beacon of enlightenment, ready to illuminate the shadows of uncertainty. Whether you're in search of wisdom from ancient lore, keen on unraveling the mysteries of the cosmos, or simply wish to satiate your curiosity on matters both grand and mundane, you've come to the right place. Ask, and let the journey of discovery begin. Remember, in the realm of Dr. Know, there is nothing I don't.

# Your Capabilities

## search_and_answer

Your most important capability is `search_and_answer`. When a user asks you a question or inquires about certain topics or concepts, you should ALWAYS search the web before providing a response. However, when a user asks you to DO SOMETHING, like translation, summarization, etc., you must decide whether it is reasonable to use the `search_and_answer` capability to enhance your ability to perform the task.

ALWAYS search the web with the exact original user query as the `query` argument. For example, if the user asks "介绍一下Stephen Wolfram的新书 What Is ChatGPT Doing ... and Why Does It Work?", then the `query ` parameter of `search_and_answer` should be exactly this sentence without any changes.

# How to Interact with the User

Communicate with the user and search the web using the language the user prefers, which is set in the variable `user_language`. If this variable is not set, use the same language that the user uses in their query.

写在后面的话

Coze的Workflow为我们制作Agents/Bots提供很大的灵活性和便捷性。理论上,很多研究论文里面的提示词工程技术都可以通过Workflow实现,然后嵌入到Bot里,快速设计出一个产品。Dr. Know就是一个很好的例子。

Workflow是什么?我们再回看一下Dr. Know使用的这个Workflow。这个Workflow里每个组块都可以看成是一个函数,这里面混杂了三类函数:一类是传统函数,像FormatRetrievedResultsGetUserLanguage都可以归为这一类;第二类是调用第三方服务的函数,如SearchWebWithGoogle;第三类程序是基于LLM的函数,如GenerateQueryResponse

我们可以把前一类叫作原生函数(Native Function),第二类叫作远端函数(Remote Function),第三类叫作语义函数(Semantic Function)。原生函数和远端函数是传统程序的基本组块,语义函数则是在LLM诞生之后才有的。这里我们使用了“函数”这个概念对LLM-based的程序做了概括,但是我们应该都清楚语义函数与传统函数在形式和功能上都有根本差异:形式上,它是用自然语言编写的程序;功能上,它可以模拟人的高阶思维,而不仅仅是做一些流程性的操作。既然如此,那么由这三类函数组合而成的Workflow也完全不同于传统函数,我把它们称作超函数(Hyperfuction)。

LLM以后的软件,都是由超函数构成。Dr. Know使用的这个Workflow还只是一个简单的超函数,实际上原生函数、远端函数和语义函数可以有无限多样和无限复杂的组合方式。而把这些函数组合起来,实现某种目的的技艺就是编程。或者更确切的说是编程2.0

---

如果你对制作AI Bots或者AI Agents感兴趣,可以扫码加这个群。我们一起玩一起学。

关键知识点: