@caretakerai/agent
v0.0.25
Published
Single framework for building text-agents
Downloads
554
Readme
Agent Framework Documentation
The Agent Framework provides a flexible and extensible environment for building intelligent agents that can perform a variety of tasks. It is built on top of the langchain
library and utilizes language models for natural language understanding and generation.
Key Components
Agent
: The core class that represents an intelligent agent. It is initialized with a set of parameters that define its behavior, capabilities, and objectives.Activity
: Represents a single unit of work or thought that the agent performs. Activities can be of different kinds, such asObservation
,Thought
, orAction
.Optimizer
: A component used to improve the agent's performance by optimizing its activities and decisions.
Initialization Parameters
When creating an Agent
, you must provide an AgentPrams
object with the following properties:
name
: The name of the agent.description
: A description of the agent's purpose and capabilities.llm
: The language model the agent will use for understanding and generating text.isChatModel
: (Optional) A flag to indicate if a chat model is used, affecting prompt formatting.typeDefs
: GraphQL type definitions for the agent's actions.resolvers
: (Optional) GraphQL resolvers for implementing the actions.executor
: (Optional) A custom GraphQL executor to handle agent actions.history
: (Optional) A list ofActivity
objects representing the agent's past experiences.examples
: (Optional) Examples of activities to guide the agent's behavior.objective
: (Optional) The goal the agent is trying to achieve.instruction
: (Optional) Completion instruction for the language model.maxIterations
: (Optional) The maximum number of iterations the agent can perform.maxRetries
: (Optional) The maximum number of retries for actions.optimizers
: The optimizer pileline used to improve the agent's performance.signal
: (Optional) An abort signal to stop the agent's operation.template
: (Optional) The template for generating prompts for the agent.stop
: (Optional) A list of strings that, if generated by the agent, should cause it to stop.logger
: (Optional) The logger the agent will use for outputting information.
Objective
The objective
is a crucial component of the Agent Framework. It defines the goal or purpose that the agent is trying to achieve. The objective is used to guide the agent's behavior and decision-making process.
const agent = new Agent({
// ... other parameters
objective: `Help the user with math calculations using specific actions.`,
});
The objective will be included in the Agent's prompt template to provide context to the language model, ensuring that the Agent's interactions are focused and relevant to the goal.
Schema
The schema is a GraphQL schema that defines the structure of the data that the agent can act upon. It includes type definitions for queries and mutations that the agent can perform. The schema is used to validate the queries and mutations that the agent receives, ensuring that they are well-formed and consistent with the agent's objectives.
Importance of a Good Schema
A good schema is essential for the QnA Agent Framework to function effectively. The schema defines the structure of the data that the agent can act upon, and it provides a clear and consistent way for the agent to interact with the user. A well-designed schema can help to:
- Improve the accuracy and relevance of the agent's responses
- Reduce the complexity of the agent's decision-making process
- Increase the efficiency of the agent's processing loop
- Enhance the overall user experience
Think of the Agent as a developer that writes the queries for you while you talk to them. When writing queries on the fly, it is essential to use a good schema to ensure that the queries are well-formed and consistent with the agent's objectives. A good schema can help to prevent errors and inconsistencies in the agent's responses, and it can improve the overall performance of the agent.
Usage
To use the QnA Agent Framework, instantiate the Agent
class with the necessary initialization parameters, including the language model, GraphQL type definitions, and resolvers. You can also include optional configurations such as history, objectives, and optimizers. Once the agent is configured, call the agent.invoke()
method to begin the agent's processing loop.
Resolvers
Resolvers are functions that implement the logic for the queries and mutations defined in the schema. They are used to retrieve or update data in response to queries and mutations.
History
Having at least one element in the history is important because it provides the agent with a starting point for its conversation with the user. This initial element in the history can be thought of as the "initial prompt" or "initial context" that sets the stage for the conversation.
Without an initial element in the history, the agent would not have any context or information to work with, and it would not know how to respond to the user's first message. By including at least one element in the history, you are providing the agent with a foundation for its conversation with the user, and it can use this information to generate more informed and relevant responses.
In the example provided, the initial element in the history is an observation that includes a message from the user asking "How can you help me?". This initial prompt provides the agent with a clear understanding of the user's intent and allows it to respond accordingly.
Here is an example of how the history is used in the agent's conversation:
history: [
new Activity({ kind: ActivityKind.Observation, input: dedent /* yaml */`
data:
say:
reply: How can you help me?
` }),
],
This initial element in the history is used by the agent to generate its first response to the user. The agent can use this information to determine the user's intent and provide a relevant response.
In general, having at least one element in the history is important because it:
- Provides the agent with a starting point for its conversation with the user
- Gives the agent context and information to work with
- Allows the agent to generate more informed and relevant responses
- Helps to establish a clear understanding of the user's intent and goals
Example
Here is an example of how to create a QnA agent that uses a language model to answer user queries:
const agent = new Agent({
name: 'QnA',
llm: new ChatOpenAI({
modelName: 'gpt-3.5-turbo-16k',
temperature: 0.7,
maxTokens: 2000,
}),
objective: dedent`
1. Help the user with finding information.
2. Search no more than 7 times before providing the answer.
3. Subsequent searches must be different from one another.
4. Prefer multiple searches to answer complex questions.
5. Prefer user language in making search queries and providing answers.
6. Prefer answers up to 300 words long.
7. Prefer descriptive answers split to paragraphs instead of lists.
`.trim(),
typeDefs: dedent /* GraphQL */`
schema {
query: Query
mutation: Mutation
}
type Query {
"""
Perform text-searches in the knowledge base and return the results as strings.
The following example shows the method of searching for information on complex topics:
<Observation>
data:
say:
reply: 'What is the difference between a white hole and a black hole?'
<Observation>
<Thought>
The user is looking for distinctive features of separate entities of the universe. I should split my search into 2.
</Thought>
<Action>
query {
blackHole: search(input: { query: "What is the nature of a black hole?" }) { result }
whiteHole: search(input: { query: "What is the nature of a white hole?" }) { result }
}
</Action>
<Observation>
data:
blackHole:
result: 'The nature of a black hole is...'
whiteHole:
result: 'The nature of a white hole is...'
<Observation>
"""
search(input: SearchInput!): SearchResult
}
type Mutation {
"""
Relay information to the user and wait for the reply. Note that this is only way of communicating information to the user.
"""
say(input: SayInput!): SayResult
}
# Inputs for mathematical operations
input SearchInput {
query: String!
}
# Inputs for say operation
input SayInput {
message: String! # The message to say to the user
}
# Result for say results
type SayResult {
reply: String # The user's reply
error: String # can be used to describe any error that occurred during the computation
}
# Result for mathematical operations
type SearchResult {
result: String
error: String # can be used to describe any error that occurred during the computation
}
`.trim(),
resolvers: {
Query: {
search: async (_, { input: { query } }) => {
try {
const chain = RetrievalQAChain.fromLLM(llm, retriever);
const { text } = await chain.invoke({ query });
return { result: text };
} catch (error) {
return { error };
}
},
},
Mutation: {
say: async (_, { input: { message } }) => {
console.log(`${chalk.bold(`${agent.name}:`)} ${message}`);
const reply = await inputPrompt({
message: 'Human:',
});
return { reply };
},
},
},
history: [
new Activity({ kind: ActivityKind.Observation, input: dedent /* yaml */`
data:
say:
reply: How can you help me?
` }),
],
optimizers: [new RemoveErrorActivitiesOptimizer(), new LengthOptimizer(16)],
});
// Invoke the agent
await agent.invoke();
This example demonstrates how to create a QnA agent that uses a language model to answer user queries. The agent is configured with a set of objectives, type definitions, and resolvers that define its behavior. The agent.invoke()
method is called to start the agent's processing loop.