from langchain_experimental.llms.ollama_functions import OllamaFunctions
from langchain_core.messages import HumanMessage
from langchain_community.tools.ddg_search.tool import DuckDuckGoSearchRun
import json
search = DuckDuckGoSearchRun()
model = OllamaFunctions(model="mistral")
model2 = OllamaFunctions(model="mistral")
model = model.bind(
    functions=[
        {
            "name": "get_current_weather",
            "description": "Get the current weather in a given location",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, " "e.g. San Francisco, CA",
                    },
                    "unit": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                    },
                },
                "required": ["location"],
            },
        }
    ],
    function_call={"name": "get_current_weather"},
)
# 使用 JsonOutputToolsParser 来试图解析结果
# https://python.langchain.com/docs/modules/model_io/chat/function_calling#binding-functions
# tool_chain = model | JsonOutputToolsParser(name="get_current_weather")
# result = tool_chain.invoke("what is the weather in Boston?")
# print(result)
# 这个方法是废的,因为这是针对OpenAI的
def get_current_weather(location):
    res = "真的是在被call哦,get_current_weather:"+location
    print(res)
    result = search.run("what is the current weather in "+location)
    return result
result = model.invoke("what is the weather in 西安?")
# 判断字符串是否是可调用的函数
#https://stackoverflow.com/questions/59912800/how-do-i-check-if-a-string-is-a-callable-name-in-python
function_call_name = result.additional_kwargs['function_call']['name']
function_call_arguments = result.additional_kwargs['function_call']['arguments']
if callable(locals()[function_call_name]):
    print(f"{function_call_name} 是当前文件中可调用的函数。")
    location_object = json.loads(function_call_arguments)
    location = location_object["location"]
    print("location:",location)
    res = eval(function_call_name)(location)
    result = model2.invoke(res+"\n\n 根据上下文,并且使用celsius来说明,使用Chineses来总结,这个城市的天气是怎样的?")
    print(result)
else:
    print(f"{function_call_name} 不是当前文件中可调用的函数。")

第一个模型负责把输入的话出发function_call的调用,可以说是100%调用的,只要出现了类似天气的关键词或者语义

然后将改写过后的location,发送给实际的python函数

这里还用了一些python的小技巧了做动态调用

这个函数就是只干了一件事,就是粘合了DDG的search而已

之后就是把搜索引擎的输出,再扔给第二个引擎

第二个引擎等于就是个不带bind_tools的白板引擎,要求它来总结我这段结果

说实话,这个function_call的行为就很迷惑

我今天下午试验了许多langchain自带的agent,还有很多tool的东西,基本都失败了

其实基本思路是对的,

1个通用引擎和用户交互,然后负责调用工具,工具的输出还是纯文字,再交给另外一个纯纯的干净的propmt的模型去格式化,总结,或者风格化

最后输出给用户就好了

感觉给LLM编程真心累

它的输入输出随着你选用的模型,会变化,就算你提示它也没求卵用

可移植性其实很差

而且再吐槽一下LangChain,就感觉很破裂的一个框架

这是结果

看看就好,因为langChain的ollama支持还停留在实验性质

我明后天再看看怎么把这个tools必call的问题解决了去

然后可能还是需要有个Router(),在前面R着

不能在LangChain上吊死,它其实真的也没干啥不是

我自手工也能搞