mw10013 / remix-cf-20240202

0 stars 0 forks source link

Function #4

Closed mw10013 closed 10 months ago

mw10013 commented 11 months ago

https://platform.openai.com/docs/guides/gpt/function-calling https://cookbook.openai.com/examples/how_to_call_functions_with_chat_models https://github.com/openai/openai-node

mw10013 commented 10 months ago

https://js.langchain.com/docs/modules/chains/popular/structured_output https://js.langchain.com/docs/modules/chains/popular/api https://js.langchain.com/docs/modules/chains/additional/openai_functions/openapi

gpt-3.5-turbo-0613 gpt-4-0613

https://js.langchain.com/docs/modules/model_io/output_parsers/output_fixing_parser

mw10013 commented 10 months ago

https://js.langchain.com/docs/modules/agents/agent_types/openai_functions_agent

const executor = await initializeAgentExecutorWithOptions(tools, chat, {
  agentType: "openai-functions",
  verbose: true,
});

export declare function initializeAgentExecutorWithOptions(tools: StructuredTool[], llm: BaseLanguageModel, options: InitializeAgentExecutorOptionsStructured): Promise<AgentExecutor>;

export type InitializeAgentExecutorOptionsStructured = ({
    agentType: "structured-chat-zero-shot-react-description";
    agentArgs?: Parameters<typeof StructuredChatAgent.fromLLMAndTools>[2];
} & Omit<AgentExecutorInput, "agent" | "tools">) | ({
    agentType: "openai-functions";
    agentArgs?: Parameters<typeof OpenAIAgent.fromLLMAndTools>[2];
} & Omit<AgentExecutorInput, "agent" | "tools">);
mw10013 commented 10 months ago

StructuredTool and Tool are two different types of tools in LangChain JS.

StructuredTool is a tool that has a defined input and output schema. This means that the tool expects a specific type of input and will produce a specific type of output. StructuredTools are typically used for tasks such as converting data formats, manipulating data, and extracting information.

Tool is a more general type of tool that does not have a defined input and output schema. This means that the tool can be used to perform a wider range of tasks, but it is important to understand the input and output requirements of the tool before using it. Tools are typically used for tasks such as interacting with external APIs and generating creative text.

Here is a table that compares and contrasts StructuredTool and Tool:

Feature | StructuredTool | Tool -- | -- | -- Input schema | Defined | Not defined Output schema | Defined | Not defined Typical use cases | Converting data formats, manipulating data, extracting information | Interacting with external APIs, generating creative text

Examples

Here are some examples of StructuredTools and Tools in LangChain JS:

The JSONToolkit.convert() function is a StructuredTool that converts JSON data to other formats, such as CSV, XML, and delimited strings. It has a defined input and output schema, which means that it expects a specific type of input (JSON data) and will produce a specific type of output (converted data).

The OpenAI.generate() function is a Tool that allows developers to call OpenAI APIs from within LangChain JS. It does not have a defined input and output schema, which means that it can be used to perform a wider range of tasks, such as generating text, translating languages, and writing different kinds of creative content.

Which one to use?

The best type of tool to use depends on the specific task that you need to perform. If you need to perform a task that has a clear input and output schema, then you should use a StructuredTool. If you need to perform a task that does not have a clear input and output schema, then you should use a Tool.

In general, it is recommended to use StructuredTools where possible. StructuredTools are easier to use and provide more predictable results. However, Tools can be useful for performing tasks that are not supported by StructuredTools.

mw10013 commented 10 months ago

https://js.langchain.com/docs/modules/agents/agent_types/structured_chat

export type InitializeAgentExecutorOptionsStructured = ({
    agentType: "structured-chat-zero-shot-react-description";
    agentArgs?: Parameters<typeof StructuredChatAgent.fromLLMAndTools>[2];
} & Omit<AgentExecutorInput, "agent" | "tools">) | ({
    agentType: "openai-functions";
    agentArgs?: Parameters<typeof OpenAIAgent.fromLLMAndTools>[2];
} & Omit<AgentExecutorInput, "agent" | "tools">);

export declare function initializeAgentExecutorWithOptions(tools: StructuredTool[], llm: BaseLanguageModel, options: InitializeAgentExecutorOptionsStructured): Promise<AgentExecutor>;
mw10013 commented 10 months ago

https://js.langchain.com/docs/modules/agents/how_to/handle_parsing_errors

const executor = await initializeAgentExecutorWithOptions(tools, model, {
  agentType: "openai-functions",
  verbose: true,
  handleParsingErrors:
    "Please try again, paying close attention to the allowed enum values",
});
mw10013 commented 10 months ago

https://js.langchain.com/docs/modules/agents/agent_types/openai_functions_agent https://js.langchain.com/docs/modules/agents/agent_types/chat_conversation_agent

  // Passing "chat-conversational-react-description" as the agent type
  // automatically creates and uses BufferMemory with the executor.
  // If you would like to override this, you can pass in a custom
  // memory option, but the memoryKey set on it must be "chat_history".
  const executor = await initializeAgentExecutorWithOptions(tools, model, {
    agentType: "chat-conversational-react-description",
    verbose: true,
  });

  // Passing "chat-conversational-react-description" as the agent type
  // automatically creates and uses BufferMemory with the executor.
  // If you would like to override this, you can pass in a custom
  // memory option, but the memoryKey set on it must be "chat_history".
  const executor = await initializeAgentExecutorWithOptions(tools, model, {
    agentType: "chat-conversational-react-description",
    verbose: true,
  });
export interface ChatConversationalCreatePromptArgs {
    /** String to put after the list of tools. */
    systemMessage?: string;
    /** String to put before the list of tools. */
    humanMessage?: string;
    /** List of input variables the final prompt will expect. */
    inputVariables?: string[];
    /** Output parser to use for formatting. */
    outputParser?: AgentActionOutputParser;
}
/**
 * Type that extends the AgentInput interface for the
 * ChatConversationalAgent class, making the outputParser property
 * optional.
 */
export type ChatConversationalAgentInput = Optional<AgentInput, "outputParser">;
/**
 * Agent for the MRKL chain.
 * @augments Agent
 */
export declare class ChatConversationalAgent extends Agent {
    static lc_name(): string;
    lc_namespace: string[];
    ToolType: Tool;
    constructor(input: ChatConversationalAgentInput);
    _agentType(): "chat-conversational-react-description";
    observationPrefix(): string;
    llmPrefix(): string;
    _stop(): string[];
    static validateTools(tools: Tool[]): void;
    /**
     * Constructs the agent scratchpad based on the agent steps. It returns an
     * array of base messages representing the thoughts of the agent.
     * @param steps The agent steps to construct the scratchpad from.
     * @returns An array of base messages representing the thoughts of the agent.
     */
    constructScratchPad(steps: AgentStep[]): Promise<BaseMessage[]>;
    /**
     * Returns the default output parser for the ChatConversationalAgent
     * class. It takes optional fields as arguments to customize the output
     * parser.
     * @param fields Optional fields to customize the output parser.
     * @returns The default output parser for the ChatConversationalAgent class.
     */
    static getDefaultOutputParser(fields?: OutputParserArgs & {
        toolNames: string[];
    }): AgentActionOutputParser;
    /**
     * Create prompt in the style of the ChatConversationAgent.
     *
     * @param tools - List of tools the agent will have access to, used to format the prompt.
     * @param args - Arguments to create the prompt with.
     * @param args.systemMessage - String to put before the list of tools.
     * @param args.humanMessage - String to put after the list of tools.
     * @param args.outputParser - Output parser to use for formatting.
     */
    static createPrompt(tools: Tool[], args?: ChatConversationalCreatePromptArgs): ChatPromptTemplate<any, any>;
    /**
     * Creates an instance of the ChatConversationalAgent class from a
     * BaseLanguageModel and a set of tools. It takes optional arguments to
     * customize the agent.
     * @param llm The BaseLanguageModel to create the agent from.
     * @param tools The set of tools to create the agent from.
     * @param args Optional arguments to customize the agent.
     * @returns An instance of the ChatConversationalAgent class.
     */
    static fromLLMAndTools(llm: BaseLanguageModel, tools: Tool[], args?: ChatConversationalCreatePromptArgs & AgentArgs): ChatConversationalAgent;
}
mw10013 commented 10 months ago
export class RunnableMap<RunInput> extends Runnable<
  RunInput,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  Record<string, any>
> {
  static lc_name() {
    return "RunnableMap";
  }

  lc_namespace = ["langchain", "schema", "runnable"];

  lc_serializable = true;

  protected steps: Record<string, Runnable<RunInput>>;

  constructor(fields: { steps: Record<string, RunnableLike<RunInput>> }) {
    super(fields);
    this.steps = {};
    for (const [key, value] of Object.entries(fields.steps)) {
      this.steps[key] = _coerceToRunnable(value);
    }
  }

  static from<RunInput>(steps: Record<string, RunnableLike<RunInput>>) {
    return new RunnableMap<RunInput>({ steps });
  }
mw10013 commented 10 months ago

System prompt with agent: https://www.reddit.com/r/LangChain/comments/14pnj5s/is_it_possible_to_have_a_conversational_agent/ https://www.reddit.com/r/LangChain/comments/13bltby/build_a_conversational_agent_that_performs_actions/

mw10013 commented 10 months ago

tools/dynamic.ts

/**
 * A tool that can be created dynamically from a function, name, and
 * description, designed to work with structured data. It extends the
 * StructuredTool class and overrides the _call method to execute the
 * provided function when the tool is called.
 */
export class DynamicStructuredTool<
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  T extends z.ZodObject<any, any, any, any> = z.ZodObject<any, any, any, any>
> extends StructuredTool {
  static lc_name() {
    return "DynamicStructuredTool";
  }

  name: string;
  description: string;
  func: DynamicStructuredToolInput["func"];
  schema: T;

  constructor(fields: DynamicStructuredToolInput<T>) {
    super(fields);
    this.name = fields.name;
    this.description = fields.description;
    this.func = fields.func;
    this.returnDirect = fields.returnDirect ?? this.returnDirect;
    this.schema = fields.schema;
  }

  protected _call(
    arg: z.output<T>,
    runManager?: CallbackManagerForToolRun
  ): Promise<string> {
    return this.func(arg, runManager);
  }
}

tools/convert_to_opeanai.ts

**
 * Formats a `StructuredTool` instance into a format that is compatible
 * with OpenAI's ChatCompletionFunctions. It uses the `zodToJsonSchema`
 * function to convert the schema of the `StructuredTool` into a JSON
 * schema, which is then used as the parameters for the OpenAI function.
 */
export function formatToOpenAIFunction(
  tool: StructuredTool
): OpenAIClient.Chat.ChatCompletionCreateParams.Function {
  return {
    name: tool.name,
    description: tool.description,
    parameters: zodToJsonSchema(tool.schema),
  };
}

tools/chain.ts

/**
 * Class that extends DynamicTool for creating tools that can run chains.
 * Takes an instance of a class that extends BaseChain as a parameter in
 * its constructor and uses it to run the chain when its 'func' method is
 * called.
 */
export class ChainTool extends DynamicTool {
  static lc_name() {
    return "ChainTool";
  }

  chain: BaseChain;

  constructor({ chain, ...rest }: ChainToolInput) {
    super({
      ...rest,
      func: async (input, runManager) =>
        chain.run(input, runManager?.getChild()),
    });
    this.chain = chain;
  }
}
mw10013 commented 10 months ago
[chain/end] [1:chain:AgentExecutor] [4.31s] Exiting Chain run with output: {
  "output": "Dr Jung's patients are Jack, Jill, June, and Keva Green.",
  "intermediateSteps": [
    {
      "action": {
        "tool": "getPatientsForDoctor",
        "toolInput": {
          "doctor": "Dr Jung"
        },
        "log": "Invoking \"getPatientsForDoctor\" with {\n  \"doctor\": \"Dr Jung\"\n}\n",
        "messageLog": [
          {
            "lc": 1,
            "type": "constructor",
            "id": [
              "langchain",
              "schema",
              "AIMessage"
            ],
            "kwargs": {
              "content": "",
              "additional_kwargs": {
                "function_call": {
                  "name": "getPatientsForDoctor",
                  "arguments": "{\n  \"doctor\": \"Dr Jung\"\n}"
                }
              }
            }
          }
        ]
      },
      "observation": "{\"patients\":[\"Jack\",\"Jill\",\"June\",\"Keva Green\"]}"
    }
  ]
}