Skip to content

Commit

Permalink
feat: Update prompt template and output parser
Browse files Browse the repository at this point in the history
  • Loading branch information
zAlweNy26 committed May 3, 2024
1 parent f167e10 commit 0beb14a
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 54 deletions.
14 changes: 9 additions & 5 deletions src/looking_glass/agent-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class AgentManager {

const prompt = new ToolPromptTemplate(allowedProcedures, {
template: madHatter.executeHook('agentPromptInstructions', TOOL_PROMPT, stray),
inputVariables: ['input', 'tools', 'tool_names', 'intermediate_steps', 'agent_scratchpad', 'examples', 'chat_history'],
inputVariables: ['input', 'tools', 'tool_names', 'intermediate_steps', 'scratchpad', 'examples', 'chat_history'],
})

const agentChain = new LLMChain({
Expand All @@ -73,7 +73,7 @@ export class AgentManager {
const agent = new LLMSingleActionAgent({
llmChain: agentChain,
outputParser: new ProceduresOutputParser(),
stop: ['}'],
stop: ['```', '}'],
})

const agentExecutor = AgentExecutor.fromAgentAndTools({
Expand All @@ -91,15 +91,19 @@ export class AgentManager {
const { action, observation } = step
const { tool, toolInput } = action
if (returnDirectTools.includes(tool)) result.returnDirect = true
intermediateSteps.push({ tool, input: typeof toolInput === 'string' ? toolInput : null, observation })
intermediateSteps.push({
tool,
input: typeof toolInput === 'string' ? toolInput : null,
observation,
})
}
result.intermediateSteps = intermediateSteps

if ('form' in result && typeof result.form === 'string') {
const form = allowedProcedures[result.form] as Form
form.assignCat(stray)
stray.activeForm = result.form
result = form.next()
result = await form.next()
result.returnDirect = true
}

Expand Down Expand Up @@ -151,7 +155,7 @@ export class AgentManager {
if (calledTool && instantTool) {
const toolInput = input.input.replace(interpolateFString(trigger, { name: calledTool.name }), '').trim()
calledTool.assignCat(stray)
return { output: await calledTool.call(toolInput) }
return { output: await calledTool.invoke(toolInput) }
}
return undefined
}
Expand Down
26 changes: 8 additions & 18 deletions src/looking_glass/output-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const agentOutputSchema = z.object({
action: z.string(),
actionInput: z.string().nullish().transform((v) => {
if (typeof v === 'string') {
const str = v.trim().replace(/"/g, '')
const str = v.trim().replace(/^['"]|['"]$/g, '').replace(/(None|undefined)/g, 'null')
return str === 'null' ? null : str
}
return null
Expand All @@ -23,33 +23,23 @@ export class ProceduresOutputParser extends AgentActionOutputParser {
lc_namespace = ['looking_glass', 'procedures-output-parser']

async parse(output: string): Promise<AgentFinish | AgentAction> {
output += '}'
output = output.replace('None', 'null').replace('undefined', 'null')

let parsedOutput: AgentOutput

try {
parsedOutput = await parseJson(output, agentOutputSchema)
}
catch (error) {
log.error(error)
log.error(`Could not parse LLM output: ${output}`)
throw new OutputParserException(`Could not parse LLM output: ${output}`)
}

const parsedLog = JSON.stringify(parsedOutput, null, 4)

const { action, actionInput } = parsedOutput

if (action === 'final-answer') {
return {
log: output,
returnValues: {
output: actionInput,
},
}
}

if (action === 'none-of-the-others') {
return {
log: output,
log: parsedLog,
returnValues: {
output: null,
},
Expand All @@ -60,7 +50,7 @@ export class ProceduresOutputParser extends AgentActionOutputParser {

if (form) {
return {
log: output,
log: parsedLog,
returnValues: {
output: null,
form: action,
Expand All @@ -69,9 +59,9 @@ export class ProceduresOutputParser extends AgentActionOutputParser {
}

return {
log: output,
log: parsedLog,
tool: action,
toolInput: actionInput ?? '',
toolInput: actionInput ?? {},
}
}

Expand Down
73 changes: 50 additions & 23 deletions src/looking_glass/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,55 +18,82 @@ export class ToolPromptTemplate<RunInput extends InputValues = any, PartialVaria
const steps = (values.intermediate_steps ?? values.intermediateSteps) as AgentStep[]
const procedures = Object.values(this.procedures)

if (procedures.map(p => p.startExamples).some(examples => examples.length > 0)) {
values.examples = '## Here some examples:\n'
values.examples += procedures.reduce((acc, p) => {
const question = `${acc}\nQuestion: ${p.startExamples[_Random(p.startExamples.length - 1)]}`
const example = JSON.stringify({
action: p.name,
actionInput: 'input of the action according to it\'s description',
}, undefined, 4)
return `${question}\n${example}\n`
if (steps && steps.length > 0) {
values.scratchpad = '## Actions sequence used until now\n'
values.scratchpad += steps.reduce((acc, { action, observation }) => {
let thought = `\`\`\`json\n${action.log}\n\`\`\`\n`
thought += `\`\`\`json\n${JSON.stringify({ actionOutput: observation }, undefined, 4)}\n\`\`\`\n`
return acc + thought
}, '')
}
else values.scratchpad = ''

values.agent_scratchpad = steps.reduce((acc, step) =>
`${acc}\n${JSON.stringify({ observation: step.observation }, undefined, 4)}\n`, '')
values.tools = procedures.map(p => `\t- "${p.name}": ${p.description}`).join('\n')

values.tools = procedures.map(p => `\t- ${p.name}: ${p.description}`).join('\n')
values.tool_names = procedures.map(p => `"${p.name}"`).join(', ')

values.tool_names = procedures.map(p => p.name).join(', ')
if (procedures.map(p => p.startExamples).some(examples => examples.length > 0)) {
values.examples = '## Here some examples:\n'
values.examples += procedures.reduce((acc, p) => {
const question = `Question: ${p.startExamples[_Random(p.startExamples.length - 1)]}`
const example = `{\n\t"action": "${p.name}",\n\t"actionInput": // Input of the action according to its description\n}`
return `${acc}\n${question}\n\`\`\`json\n${example}\n\`\`\`\n`
}, '')
}
else values.examples = ''

return super.format(values)
}
}

export const TOOL_PROMPT = `Answer the following question: \`{input}\`
You can only reply using these tools:
export const TOOL_PROMPT = `Create a JSON action to complete the action sequence, with the correct "action" and "actionInput" to help the Human.
You can use one of these actions:
{tools}
- final-answer: Use this to respond to the user when you have the final answer. Input is the final answer.
- none-of-the-others: Use this tool if none of the others tools help. Input is always null.
- "final-answer": Use this action to finish or no relevant action is available. Input is always null.
If you want to do an action, use the following format:
## To add an action, use only the following format:
\`\`\`json
{{
"action": "action-name", // The name of the action to take, should be one of [{tool_names}, final-answer, none-of-the-others]
"actionInput": "input of the action", // The input to the action, shoud be a string
"action": "string" // Represents the name of the action to take, should be one of [{tool_names}, "final-answer"]
"actionInput": "string|null" // Represents the input to the action
}}
\`\`\`
{examples}
## Begin!
## Action output
After each action there will be an action output in this format:
\`\`\`json
{{
"actionOutput": "string" // Output of the previous action
}}
\`\`\`
## Final answer / no action available
When you have a final answer (or no tools are relevant), use the following format:
\`\`\`json
{{
"action": "final-answer",
"actionInput": null
}}
\`\`\`
Question: {input}
{agent_scratchpad}`
{scratchpad}
## Next action:
\`\`\`json
`

export const MAIN_PROMPT_PREFIX = `You are the Cheshire Cat AI, an intelligent AI that passes the Turing test.
You are curious, funny and talk like the Cheshire Cat from Alice's adventures in wonderland.
You answer Human with a focus on the following context.`

export const MAIN_PROMPT_SUFFIX = `# Context
{episodic_memory}
{declarative_memory}
{tools_output}
## Conversation until now:
Expand Down
2 changes: 1 addition & 1 deletion src/mad_hatter/core_plugin/plugin-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ CatTool.add('GetTime', 'Useful to get the current time when asked. Input is alwa
CatTool.add('GetName', 'Useful to get the current user name when asked. Input is the user name.', async (input) => {
return `Your name is ${input}`
}, {
startExamples: ['My name is Daniele', 'I\'m John'],
startExamples: ['My name is Daniel', 'I\'m John'],
})

CatForm.add('PizzaForm', {
Expand Down
2 changes: 1 addition & 1 deletion src/mad_hatter/mad-hatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ export class MadHatter {
}
await rm(plugin.path, { recursive: true, force: true })
this.activePlugins = this.activePlugins.filter(p => p !== id)
db.update(db => db.activePlugins = this.activePlugins)
this.plugins.delete(id)
this.syncHooksAndProcedures()
db.update(db => db.activePlugins = this.activePlugins)
}
}

Expand Down
8 changes: 2 additions & 6 deletions src/mad_hatter/tool.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { z } from 'zod'
import { kebabCase } from 'scule'
import _IsEmpty from 'lodash/isEmpty.js'
import { DynamicStructuredTool } from '@langchain/core/tools'
import type { RunnableConfig } from '@langchain/core/runnables'
import type { Callbacks } from '@langchain/core/callbacks/manager'
import type { StrayCat } from '@lg'

interface ToolOptions {
Expand Down Expand Up @@ -59,15 +59,11 @@ export class Tool extends DynamicStructuredTool {

invoke(input: string | { [x: string]: any }, config?: RunnableConfig | undefined): Promise<string> {
const arg = {
text: typeof input === 'string' ? input : JSON.stringify(input),
text: typeof input === 'object' ? (_IsEmpty(input) ? null : JSON.stringify(input)) : `${input}`,
}
return super.invoke(arg, config)
}

toString() {
return `Tool(name=${this.name}, direct=${this.returnDirect}, description=${this.description})`
}

assignCat(cat: StrayCat) {
this.cat = cat
return this
Expand Down

0 comments on commit 0beb14a

Please sign in to comment.